The Ball Is Already at the Bottom: Reading the ‘I Had Potential’ Ramp Diagram

The shirt shows four words in white capitals: I HAD POTENTIAL. Beneath them, a white curved ramp descends from an upper-left ledge to a lower-right flat ledge. At the top of the ramp, on the upper-left ledge, sits a dashed empty circle. At the bottom, on the lower-right flat ledge, rests a solid white ball. The ramp is curved, not a straight diagonal. That is the entire design.

Most readings of this shirt stop at the phrase. The joke is taken to be the gap between what the wearer once was and what the wearer now is — a self-deprecating caption with no further structure. But the drawing is doing something more specific than that, and the specificity is what makes the object worth looking at closely. The dashed circle and the solid ball are not decoration. They are a before-and-after in a single frame, and the ramp between them is the part that carries the argument.

In physics, potential energy is stored energy — the energy an object has by virtue of its position in a field. A ball at the top of a ramp has gravitational potential energy relative to the bottom. Release it, and that potential converts into kinetic energy as it rolls down. The phrase I had potential borrows the vocabulary of that conversion and applies it to a person. The joke is that the conversion has already happened, and the result is a ball sitting still on a flat ledge.

What the drawing adds is the direction of travel. The dashed circle is at the upper left, empty — a position once occupied, now vacated. The solid ball is at the lower right, resting. The ramp curves between them. Read left to right, the diagram is a trajectory: something started high, descended, and stopped. The dashed outline is the ghost of the starting position. The solid ball is the current state. The curve is the path, and the flat ledge at the bottom is where motion ends.

That is a more precise joke than the phrase alone. I had potential is a sentence about the past. The diagram is a diagram about conversion — potential becoming motion becoming rest. The shirt is not just saying the potential is gone; it is showing the mechanism by which it went. The ball did not evaporate. It rolled down a curved ramp and came to rest on a flat surface. The potential was real. The conversion was real. The result is a ball that is no longer moving.

There is a second reading available, and it depends on the same visual facts. The dashed circle is empty. The solid ball is present. If you read the diagram right to left — from the resting ball back up the ramp to the empty circle — you get the reverse: a ball at rest, a path upward, and a position that is now vacant. That reading is less natural, because ramps descend and balls roll down, but it is not impossible. The dashed circle could be a destination rather than an origin. The shirt does not resolve this. The ambiguity is part of what makes the drawing work as a drawing rather than as a caption.

The phrase itself is common enough that the shirt is not relying on novelty of wording. What distinguishes this object is the pairing: a terse self-description above a small physics diagram that literalizes the metaphor. The diagram is minimal — two ledges, one curve, two circles — and it is rendered in the same white as the text. There is no color coding, no labels, no axes. The viewer supplies the physics. That is the right amount of information for a shirt: enough to reward a second look, not so much that it becomes a lecture.

For technical readers, the appeal is probably not the physics itself, which is elementary, but the structure of the joke. It is a diagram that admits a failure mode. The ball is at the bottom. The potential is spent. The system has reached equilibrium, and equilibrium is another word for nothing further happening. That is a familiar shape of story in operations work: a system that once had headroom, a conversion that happened, and a steady state that is technically stable and practically inert. The shirt does not say any of that. It just shows a ball on a ledge and lets the viewer complete the analogy.

The design is available as a standard t-shirt from Quirky Cotton Collective: I Had Potential Funny Physics Pun Sarcastic Minimalist Quote. The retail title calls it a physics pun and a sarcastic minimalist quote, which is accurate as far as it goes, but the drawing is the part that earns the description. A shirt with only the words would be a slogan. The ramp and the two circles make it a small argument about what happens to potential after it converts.

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

The Roots Are the Argument: Reading the ‘Let’s Root for Each Other’ Shirt

The shirt reads LET’S ROOT FOR EACH OTHER AND WATCH EACH OTHER GROW, set in a ring around four smiling root vegetables: a carrot, a radish, a beet, and an onion. Each one is drawn with its roots visible in soil. The roots are not decorative. They are the visual hinge on which the whole sentence turns.

That sentence contains two meanings of root, and the artwork knows it. To root for someone is to support them from the sidelines. To put down roots is to establish yourself in place. The design stacks both readings on top of each other and then adds a third: the vegetables are literally roots, pulled from the ground, smiling anyway. The pun is not just a pun. It is a small argument about what mutual support actually looks like when it is not a slogan.

Most workplace encouragement is directional. One person with more authority or more visibility cheers on another person with less. The cheer is real, but the relationship is asymmetric. The shirt’s phrasing is not. Each other appears twice, and both times it is reciprocal. The support runs in both directions, and so does the growth. The carrot is not mentoring the radish. The beet is not sponsoring the onion. They are all in the same soil, and the sentence treats that shared position as the precondition for everything else.

The second half of the line is where the design gets more interesting. Watch each other grow is a strange thing to promise. Watching is passive. Growth is slow. The phrase does not say make each other grow or help each other grow. It says watch. That is a lower-commitment verb, and I think it is the more honest one. You cannot actually make a colleague get better at their job. You can notice when they do. You can say so. You can leave room for the part of growth that happens underground, where nobody can see it yet.

The roots in the illustration make that point visually. They are drawn below the soil line, visible to the viewer but not to the other vegetables. Each root system is its own tangle. The carrot’s root is long and tapered. The beet’s is rounder, more fibrous. The onion’s is a spray of thin threads. They are not sharing a root system. They are sharing soil. That distinction matters. Mutual support does not mean merging into one organism. It means four separate organisms, each with its own underground work, occupying the same patch of ground and not crowding each other out.

I keep coming back to the onion. It is the only vegetable in the group that is a bulb rather than a taproot, and it is drawn with its papery skin and its green shoots still attached. It looks slightly out of place next to the carrot and the beet, which are classic root crops. The radish is somewhere in between. The design does not smooth over that difference. It puts four different root architectures in a row and gives them all the same smile. The visual message is not we are all the same. It is we are all rooted, and we are all here.

There is a version of this shirt that would be worse. It would say something like Teamwork Makes the Dream Work and put a cartoon sun in the corner. That shirt would be making a demand. This one is making an observation. The difference is in the verb. Root for is something you do from where you are. Watch is something you do with your attention. Neither one requires you to perform enthusiasm you do not feel. Neither one asks you to pretend that growth is fast or linear or evenly distributed. The vegetables are smiling, but they are also just sitting there in the dirt, which is what roots do.

The phrase let’s root for each other shirt is the kind of search that probably comes from someone looking for a gift for a gardener, a coworker, or a friend who has been quietly doing the unglamorous work for a while. The design suits that use because it does not overpromise. It is a shirt about the conditions that make growth possible, not a shirt about growth itself. The soil is the shared thing. The roots are the private thing. The smile is the part you can see.

If you want the object itself, it is listed here: Let’s Root For Each Other And Watch Each Other Grow Garden from Quirky Cotton Collective. The design is what the listing shows: the full sentence wrapping four smiling root vegetables with their roots visible in soil. I am not going to tell you how it wears, because I have not worn it. I am going to tell you what the artwork argues, because that is the part I can actually read.

The argument is this: support is not a transaction, and growth is not a deliverable. The shirt puts both ideas in the same sentence and then draws them as vegetables in the ground. The roots are the part you cannot see from above. The smile is the part you can. The sentence asks you to pay attention to both.

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

The Period After ‘meh’ Is the Whole Design: Reading the Small Lowercase Shirt

The garment preview shows a dark shirt with a single word centered on the chest: meh. Lowercase, very small, followed by a period. No illustration, no animal, no slogan stacked above or below it. The scale is the first thing I notice, because it is not the scale of a joke that wants to be read across a room. It is the scale of a message that expects you to be standing close enough to care, and then tests whether you actually do.

Most text shirts fail by overexplaining. They give you a setup, a punchline, and a font choice that says please laugh. This one gives you four characters and a punctuation mark, and the punctuation mark is doing more work than the letters. A period is a full stop. It is the typographic equivalent of closing a ticket with no comment. The word alone could be a shrug; the period makes it a verdict.

I keep thinking about this in the context of the messages technical people actually send each other. The best incident updates I have read are not eloquent. They are short, lowercase, and final: fixed. rolled back. meh. The last one is not a status you want in a postmortem, but it is an honest status for a lot of things that do not deserve a paragraph. The shirt is not making a software argument. It is making a typographic one, and the typographic argument happens to map onto a habit of mind that a lot of operators share: say less, mean it, stop.

Small type is a boundary, not a whisper

There is a common assumption that small print is timid. In practice, small print is often the most confident choice on a page. A large slogan asks for attention before it has earned it. A small one waits. It says: I am not going to shout at you, and I am not going to explain myself twice. That is a boundary statement, and boundaries are a recurring theme in the work-culture conversations technical readers tend to have — the difference between a slogan and a usable promise, between a team value and a thing a team actually does.

The meh. here is not a promise. It is a refusal to make one. That is what makes it usable as an off-duty object rather than a work object. You would not put it on a status page. You might put it on a shirt, where the stakes are low and the audience is whoever is close enough to read it. The smallness enforces the intimacy. If someone comments on it, they were standing near you and looking at your chest long enough to parse four lowercase letters. That is already a filter.

The meh shirt is sold under the Quirky Cotton Collective brand, and the listing title stacks up the usual retail adjectives — funny, sarcastic, introvert, minimalist. I would not treat those words as printed on the garment. The preview shows one word and a period. The rest is catalog prose, and catalog prose is not evidence of what the shirt says. What the shirt says is meh. What the listing says is a set of search-friendly descriptors. The gap between those two things is worth noticing, because it is the same gap between a service’s marketing page and its actual behavior under load.

The period is the part I would keep

Strip the period and you have a different object. meh without punctuation is a sound, an exhale, a verbal shrug that trails off. meh. with the period is a closed statement. It has a beginning and an end and no invitation to continue. In a work culture that runs on open loops — the follow-up, the check-in, the circling back — a closed loop printed at four-point scale is a small act of defiance. It is not rude. It is just done.

I do not think the design is making a claim about introversion, despite the listing title. Introversion is a psychological category, and a shirt is not a personality test. What the design actually does is borrow the visual grammar of understatement and apply it to a word that already means understatement. That is a tautology, but it is a well-executed one. The lowercase letters sit at the same weight as the period, so the whole thing reads as a single unit rather than a word with a dot after it. The centering is plain. There is no drop shadow, no distressed texture, no faux-vintage treatment. It is as bare as a design can be while still being a design.

That bareness is the argument. A shirt like this works only if you accept that the joke is the restraint. If you want the joke explained, you will be disappointed. If you want a shirt that says I have opinions but I am not going to spend the afternoon defending them, the restraint is the point. The period is the part I would keep if I were editing it. Without the period, it is a mood. With the period, it is a position.

What it is not

It is not an animal shirt. The preview shows no illustration, and the listing does not describe one. It is not a pride variant. It is not a diagram joke, a regex joke, or a reference to a specific protocol. Readers who come to this column for the diagram shirts will find less to unpack here, and that is fine. Not every object needs a hidden layer. The hidden layer, if there is one, is the punctuation, and I have already spent more words on it than the shirt spends on itself.

It is also not a cure for anything, a productivity system, or a statement about mental health. It is a word on a shirt. The useful question is not what it does for you but what it declines to do: it declines to elaborate, decline to perform enthusiasm, and decline to turn a mood into a manifesto. For a certain kind of technical reader — the one who has learned that the shortest accurate message is usually the one that survives the incident review — that refusal is legible. It is not a slogan. It is a full stop.

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

Scheduling restic check and Borg check without locking out production backups

Integrity checks fail in two ways. The obvious one is that they find corruption. The less obvious one is that they never run, or run so rarely that a repository can rot for a year before anyone notices. For a small fleet — one to ten machines, one operator, a VPS or two and a homelab box — the second failure mode is the common one, and it is almost always a scheduling problem dressed up as a discipline problem.

The instinct is to bolt restic check or borg check onto the end of the nightly backup script. That instinct is wrong, but not for the reason usually given. The contention that matters is not between a read-only check and a backup. It is between the maintenance jobs that take exclusive locks — prune, forget, compact — and the backup that is trying to write while they hold the repository. A check scheduled carelessly next to a prune is how you get a backup that fails at 02:15 and a check that reports clean at 02:20, and nobody looks at either until a restore is needed.

The lock is the schedule

Restic’s own documentation is blunt about this. In the section on removing snapshots: “During a prune operation, the repository is locked and backups cannot be completed. Please plan your pruning so that there’s time to complete it and it doesn’t interfere with regular backup runs.” The same page adds: “It is advisable to run restic check after pruning, to make sure you are alerted, should the internal data structures of the repository be damaged.”

That is the whole design constraint in two sentences. Prune is the disruptive job. Check is the job that should follow it, because prune is the operation most likely to expose a structural problem. If you schedule them as one maintenance window, you get the check for free at the moment it is most informative. If you schedule them as two independent cron entries an hour apart, you have created a race between a job that holds an exclusive lock and a job that needs to read the repository, and you have done so for no benefit.

Borg’s situation is different in detail and similar in shape. borg check is read-only by default: “The check command is a read-only task by default. If any corruption is found, Borg will report the issue and proceed with checking. To actually repair the issues found, pass --repair.” The retrieved Borg documentation does not state whether check takes a repository lock or blocks a concurrent create, so do not assume either way. What it does state is that check “always needs the key, --repository-only included: it loads the key (asking for the passphrase, if needed) before it checks anything and aborts if the key can not be loaded.” That matters for scheduling: a check that cannot read the key fails before it touches the repository, and a cron job that swallows that failure looks identical to a clean run.

Restic: separate the jobs, then spread the reads

The practical restic pattern for a small fleet is three jobs, not one:

  1. Backup, nightly, on the production host, with a credential that can write but not delete.
  2. Forget and prune, weekly, on a maintenance host that holds the delete-capable credential.
  3. Check, immediately after prune, on the same maintenance host, in the same window.

Keeping the delete-capable credential off the production host is the append-only pattern, and it is worth the extra host because it changes what a compromised production server can do to your history. It also means the maintenance host is the natural place to run the check: it already has the password, it already has the repository access, and it is not competing with a backup for I/O on the machine that is actually serving users.

The check itself does not have to read every pack every week. Restic’s check accepts --read-data-subset, which resticprofile’s reference documents as: “read a subset of data packs, specified as ‘n/t’ for specific part, or either ‘x%’ or ‘x.y%’ or a size in bytes with suffixes k/K, m/M, g/G, t/T for a random subset.” The n/t form is the one to use for a schedule, because it is deterministic: day 1 of 31, day 2 of 31, and so on. Over a 31-day month every pack is read once. Over a 30-day month, one group is skipped until the next long month — a real gap, but a bounded one, and far better than a full read-data check that never fits in the window and therefore never runs.

A percentage subset is simpler to write and worse to reason about. Restic’s own documentation notes that random subsets do not guarantee full coverage. If you use a percentage, you are choosing probabilistic coverage and you should say so in the runbook rather than pretending the schedule is exhaustive.

One more restic detail worth knowing before you panic at the output: restic check routinely reports pack files that are not referenced in any index. The FAQ is explicit that this is “not a source for concern” and is “with high probability this is duplicate data caused by an interrupted backup run or upload operation,” cleanable with restic prune. A check that exits clean but prints those lines is a pass, not an incident. Teach your alerting the difference, or you will page yourself at 3 a.m. for an interrupted upload from three weeks ago.

Borg: time-box the repository check, keep verify-data rare

Borg’s check splits into two phases that behave very differently under a schedule. The repository phase checks segment headers and the metadata and data of all objects, with size and CRC checks that catch bit rot. The archive phase checks archive metadata and, optionally with --verify-data, the actual file content.

The repository phase can be time-boxed. From the Borg 1.4 documentation: “The --max-duration option can be used to split a long-running repository check into multiple partial checks. After the given number of seconds the check is interrupted. The next partial check will continue where the previous one stopped, until the full repository has been checked.” The same page gives the arithmetic: a complete check that would take seven hours, run daily with --max-duration=3600, produces one full repository check per week.

There is a catch, and it is the one that bites people who skim. Partial repository checks cannot run archive checks. The 1.4 documentation states that with --max-duration “you must also pass --repository-only, and must not pass --archives-only, nor --repair.” The 2.x documentation repeats the constraint and adds the reason: partial checks “run neither archive checks nor repair mode.” So a time-boxed daily check verifies the repository’s bytes but says nothing about whether the archives’ metadata and chunk references are consistent. You need a separate, less frequent archive check to cover that half.

Borg 2.x adds --max-age, which lets a check reuse recent pack results: “packs whose intact result is younger than the given timespan (e.g. --max-age=4w or --max-age=12m) are skipped, spreading the verification cost over repeated checks.” This is not available in 1.x, so check which major version you are running before copying a schedule from a 2.x page. The 2.x documentation also notes that --max-age “affects only the repository check and cannot be combined with --archives-only or --repair.”

Then there is --verify-data. The 1.4 documentation calls it “a complete cryptographic verification and hence very time consuming, but will detect any accidental and malicious corruption.” The 2.x documentation is more emphatic: it “always verifies that each chunk’s content matches its chunk id, which normal reads do not do by default” and “running it periodically is therefore recommended.” Periodic does not mean nightly. For a small fleet, a monthly or quarterly --verify-data run, scheduled in a window long enough to finish, is the honest cadence. Putting it on a daily timer and hoping it completes is how you get a check that is killed halfway every night and never reports anything useful.

A schedule that fits one to ten machines

The following is a recommendation, not a finding. It assumes a nightly backup window, a maintenance host with delete rights, and a repository small enough that a full read-data pass is measured in hours rather than days. Adjust the cadences to your window; do not adjust the separation.

  • Nightly, production host: backup only. No check, no prune, no forget. The production host should not be able to delete its own history, and it should not be doing maintenance work while it is also serving.
  • Weekly, maintenance host: forget --prune, then restic check (structural, no --read-data) in the same window. This is the check the restic docs recommend after pruning.
  • Daily, maintenance host, staggered hours from the backup: restic check --read-data-subset=n/31, where n is the day of the month. Or, for Borg, borg check --repository-only --max-duration=3600 (1.x) or with --max-age=1w added (2.x).
  • Monthly, maintenance host: a full archive check. For Borg, borg check --archives-only without --max-duration. For restic, a full --read-data run if the repository is small enough, or accept the subset rotation as your coverage.
  • Quarterly, maintenance host: borg check --verify-data if you run Borg, in a window you have actually measured.

Stagger by hours, not minutes. If prune and check both need the repository and the prune takes longer than expected — and it will, the first time, because the first prune after a policy change repacks more than you think — a five-minute gap is a coin flip. A multi-hour gap is a schedule. Put the check after the prune in the same window, and put the daily partial check in a different window entirely, ideally at a time when no backup is running on any host that shares the repository.

Alert on “did not run” separately from “found errors”

This is the part that separates a schedule from a comfort ritual. A check that exits 0 because it found nothing and a check that exits 0 because it was skipped by a lock, or because the key was not readable, or because the wrapper swallowed a non-zero exit, look identical to a naive monitoring setup. They are not identical. One means the repository is intact. The other means you do not know.

Borg’s return codes are documented and worth wiring into your wrapper: 0 is success, 1 is a generic warning where “operation reached its normal end, but there were warnings — you should check the log,” 2 is a generic error, and with BORG_EXIT_CODES=modern the codes become more specific. A wrapper that treats anything other than 0 as a failure and anything other than 0 or 1 as a page is a reasonable starting point. Restic’s exit behavior is less granular, so the wrapper should also check that the check actually ran: a start timestamp, an end timestamp, and a duration that is not suspiciously short.

The failure mode to design against is the green check that never executed. If your monitoring only alerts on non-zero exits, a cron entry that silently stopped firing three months ago is invisible. Alert on the absence of a successful run, not just on the presence of a failed one.

What a clean check does not prove

A clean restic check or borg check proves the repository is internally consistent. It does not prove the repository contains what you need. A backup job that has been silently excluding the wrong directory for six months will produce a perfectly consistent repository with nothing useful in it, and every check will pass.

Pair the check schedule with a periodic restore test. Restore a file, restore a directory, restore a database dump, and time it. The check tells you the bytes are intact; the restore tells you the bytes are the right bytes. Neither substitutes for the other, and a schedule that only does the first is a schedule that will pass every test until the day it matters.

Before you trust the schedule

Three things to verify before you walk away from the cron file:

  1. Dry-run the policy. restic forget --dry-run and borg prune --dry-run print what would be removed without removing it. Run them once by hand, read the output, and confirm the retention rules match your intent. A policy that keeps nothing is a policy that will delete your history on the first real run.
  2. Confirm which host holds delete rights. If the production host can delete, the append-only split is not in place, and the check schedule is protecting a repository that a compromised server can still destroy.
  3. Restore something. Not a dry run, not a listing. An actual restore to a scratch directory, from the most recent snapshot, with the clock running. If it takes longer than your recovery objective allows, the check schedule is not the problem.

FAQ

Does restic check take an exclusive lock and block backups?

The retrieved restic documentation states that prune locks the repository and that backups cannot be completed during a prune. It does not state check‘s locking behavior. Do not assume either way; test it against your restic version, or simply schedule the check outside the backup window so the question does not matter.

Does borg check block a concurrent borg create?

The retrieved Borg check documentation does not state whether check takes a repository lock or blocks a concurrent create. It does state that check is read-only by default and that it always needs the key. Treat the lock question as open and schedule accordingly.

Can I use --max-duration with --archives-only?

No. Both the 1.4 and 2.x documentation state that --max-duration requires --repository-only and cannot be combined with --archives-only or --repair. A time-boxed check covers the repository phase only; archive checks need a separate, untimed run.

Is --max-age available in Borg 1.x?

It appears on the 2.x check documentation page and not on the 1.4 page. Check your version before using it in a schedule.

Why does restic check report packs not referenced in any index?

Restic’s FAQ describes this as uncritical, most likely duplicate data from an interrupted backup or upload, and cleanable with restic prune. It is not by itself a sign of corruption.

How often should I run --verify-data?

Borg’s 2.x documentation recommends running it periodically because normal reads do not verify chunk content against chunk IDs. The right cadence depends on your repository size and your window; for a small fleet, monthly or quarterly is a defensible starting point, provided the run actually completes. A daily --verify-data that gets killed halfway every night is worse than a quarterly run that finishes.

Monitoring Certificate Chains From the Inside: Three Probes, Three Failure Modes

A certificate check that returns a single boolean is not a monitor. It is a coin flip with extra steps. Expiry, trust-path validation, and revocation are three different questions, answered from three different data sources, and they fail in three different ways. Collapse them into one green light and the light will be wrong in at least one direction — usually the direction that gets you paged.

This is about probing your own endpoints from inside your network: the mail server, the reverse proxy, the internal API. It is not about watching Certificate Transparency logs for your domains. Those answer a different question — what has been issued in your name — and they fail differently. Keep them separate.

Why one check hides the interesting failures

RFC 5280 profiles the X.509 v3 certificate and the X.509 v2 CRL, and it describes an algorithm for certification path validation. That algorithm is the thing your TLS client actually runs. It checks signatures up the chain, validity periods at every depth, name constraints, key usage, and — if configured — revocation status. A monitor that only reads the leaf’s notAfter is checking one input to that algorithm and calling it a day.

The failure modes you care about are not the same failure:

  • Expiry is a property of each certificate in the chain, not just the leaf. An intermediate that expires before the leaf takes the whole endpoint down.
  • Trust-path failures are structural: a missing intermediate, a cross-signed alternate chain, a root that your trust store does not carry, a name mismatch. These are usually binary, but the reason is what you need.
  • Revocation is a network question with a third answer. The responder can say good, revoked, or unknown — and it can also fail to answer at all, which is not the same as good.

Each of these deserves its own probe, its own state model, and its own alert path.

Probe 1 — chain and trust

Verify the served chain against your own trust store, not the system default, and read the structured output rather than the exit status. The OpenSSL verify command verifies certificate chains and, per its manual, attempts to display all problems if a chain has multiple. That last property matters: a chain can have more than one defect, and fixing the first one you see may just reveal the second.

The output format is documented. The general shape is:

server.pem: /C=AU/ST=Queensland/O=CryptSoft Pty Ltd/CN=Test CA (1024 bit)
error 24 at 1 depth lookup: invalid CA certificate

The manual is explicit about depth: it starts at zero for the target (leaf) certificate, then 1 for the CA that signed it, and so on. That number is the difference between a five-minute fix and an hour of guessing. error 24 at 1 depth tells you the intermediate is the problem. error 10 at 0 depth tells you the leaf has expired. error 20 at 0 depth tells you the issuer cannot be found — usually a missing intermediate in what the server sends.

A probe that only checks $? throws that away. Parse the error number and the depth. Store both. Alert on the pair, not on the exit code.

Two practical notes on running this:

  • Fetch the chain the way a client would — openssl s_client -showcerts against the endpoint — and feed the leaf plus the served intermediates to verify with -untrusted, and your own roots with -CAfile or -CApath. If you verify against a different trust store than your clients use, you are testing a different system.
  • If you want the probe to also exercise revocation, verify accepts -CRLfile (a file or URI containing one or more CRLs) and -crl_download, which attempts to download CRL information via the certificates’ CDP entries. Both are useful, but see the revocation section below before you make them the primary signal.

Probe 2 — expiry, at every depth

The leaf is the certificate everyone watches. The intermediate is the one that surprises people, because it was issued years ago, renewed on someone else’s schedule, and is not in your renewal runbook.

The probe should extract notBefore and notAfter for every certificate in the served chain, compute the earliest expiry, and report which certificate at which depth owns it. A chain where the leaf has 200 days left and the intermediate has 12 is a chain with 12 days left.

This is also where cross-signed and alternate chains complicate things. A server may present one chain; a client may build a different path using a cross-signed root or an alternate intermediate it already has cached. Your probe sees what the server sends. That is the right thing to monitor for your endpoints, because it is what most clients will receive — but be aware that a successful verification on your probe does not prove every client will build the same path. If you care about a specific client population, probe with that population’s trust store.

Probe 3 — revocation, and the state everyone forgets

OCSP is specified in RFC 6960 as a protocol for determining the current status of a certificate without requiring CRLs. It defines three definitive status values: good, revoked, and unknown. Read the definitions before you write alert rules, because two of them do not mean what the words suggest.

good is narrower than it sounds. The RFC states that a good response does not necessarily mean the certificate was ever issued, or that the time the response was produced falls within the certificate’s validity interval. It means the responder has no current record of revocation for that serial. It is not a statement that the certificate is valid for your use.

unknown means the responder does not know the certificate, usually because the request names an issuer that responder does not serve. It is not a revocation. It is not a clean bill of health either. It means the status could not be determined by this responder, and the client is left to decide whether to try another source.

revoked is the only one that is unambiguously bad news, and even that has a wrinkle: RFC 6960 permits a responder to return revoked for a certificate that was never issued, provided it includes the extended revoked definition extension and sets the revocation reason to certificateHold with a revocation time of January 1, 1970. If you are parsing responses by hand, do not assume revoked implies a real issuance history.

Then there is the fourth outcome, which the protocol does not call a status at all: the responder did not answer. RFC 6960 defines error responses — malformedRequest, internalError, tryLater, sigRequired, unauthorized — and states plainly that these messages are not signed. tryLater specifically indicates the service exists but is temporarily unable to respond.

This is where most homegrown probes go wrong. The HTTP request times out, the script catches the exception, logs a warning, and returns success — because the certificate itself is fine, right? The certificate may well be fine. You do not know. That is the point.

The design rule: every probe needs a third state

Every probe should return one of three things: healthy, failed, or could not determine. The third state must never be collapsed into healthy. A probe that cannot reach the OCSP responder has not established that the certificate is unrevoked. A probe that cannot reach the endpoint has not established that the certificate is valid. A probe whose own execution failed has told you nothing about the target.

This is not a stylistic preference. It is the difference between a monitor and a random number generator. The failure mode of a silent probe is identical, from the alerting system’s perspective, to a healthy endpoint: no page. You will discover the difference during the incident, which is the worst possible time.

Concretely, the three-state model means:

  • A timeout or connection error from the OCSP responder is could not determine, not healthy.
  • An OCSP unknown response is could not determine unless you have a documented policy that says otherwise for that issuer.
  • A verify invocation that fails to run — missing binary, unreadable trust store, malformed chain file — is could not determine, not a pass.
  • A verify run that completes with errors is failed, with the error code and depth attached.

Write the policy down before you write the code. What do you do with unknown? What do you do with tryLater? What do you do when the responder is reachable but its response is stale — outside the thisUpdate/nextUpdate window? If you do not decide, the default behavior is whatever your tool happens to do, which is usually to treat the absence of a clear failure as success.

A worked example of the failure this prevents

Consider a probe that does the following: fetch the chain, run verify against the local trust store, then query the OCSP responder named in the leaf’s AIA extension. If the OCSP query throws, catch it and continue. Return success if verify passed.

Now suppose the responder is down for maintenance, or the network path from your probe host to the responder is blocked by a firewall change nobody documented. The probe returns green. The certificate may in fact be revoked — you would not know, because you never got an answer. The monitor has reported health it did not observe.

Under the three-state model, the same probe returns could not determine with the responder URL and the error attached. That is a page, or at minimum a ticket, and it is the correct response: your revocation checking is broken, and you should know that before you need it.

What to log on every run

The value of a probe is not the current status. It is the record that lets you diagnose a failure six months from now without re-running against an endpoint that may have changed. Log, at minimum:

  • The chain as served: subject, issuer, serial, notBefore, notAfter, and depth for each certificate.
  • The verify result: exit status, every error number, and every depth reported.
  • The trust store used, by path and by content hash if you can manage it.
  • For revocation: the responder URL, the response status, thisUpdate, nextUpdate, and producedAt if present.
  • For any indeterminate result: the specific error — timeout, TLS failure, HTTP status, OCSP error name.

The thisUpdate/nextUpdate window is particularly worth keeping. A responder that is reachable but serving stale responses is a different problem from a responder that is unreachable, and the two require different fixes. If you only log “OCSP OK”, you cannot tell them apart later.

What this does not cover

Two things are deliberately out of scope, and it is worth being explicit about why.

Certificate Transparency. CT logs are append-only ledgers of certificates that anyone can query, and a monitor can compute an audit proof to verify that a particular certificate exists in a log. That is a valuable check — it tells you whether someone issued a certificate for your domain that you did not request. But it answers a question about the public record, not about the certificate your server is currently presenting. A CT monitor and a local endpoint probe fail in different ways and should be operated as separate concerns.

CAA records. RFC 8659 is explicit that relying parties must not use CAA records as part of certificate validation. CAA is an issuance-time control that CAs check before issuing. It is not a validation input, and a probe that reads CAA and treats it as a trust signal is doing something the specification forbids.

FAQ

Can I just use openssl verify with -crl_check and be done?

You can, and it will catch some things. But -crl_check depends on having a current CRL available, either via -CRLfile or via -crl_download against the certificate’s CDP entries. If the CRL cannot be fetched, you need to know whether the tool treated that as a failure or as a pass, and you need to know which. The three-state model applies here too: a CRL fetch failure is could not determine.

What is the difference between an OCSP unknown and a responder error?

unknown is a signed, definitive response saying the responder does not know the certificate — usually because it does not serve that issuer. A responder error is an unsigned message saying the request could not be processed. RFC 6960 lists the error types and states that error messages are not signed. They are different failure modes and should be logged differently.

Should I alert on unknown?

That is a policy decision, and you should make it deliberately. If your issuer’s responder returns unknown for certificates it should know about, that is a problem worth investigating. If it returns unknown for a certificate from a different issuer because you queried the wrong responder, that is a probe bug. Either way, treating unknown as healthy by default is the one option that is hard to defend.

Why not just check the leaf’s expiry and call it monitoring?

Because the intermediate can expire first, and because expiry is only one of the three questions. A chain with a valid leaf and an expired intermediate fails path validation. A chain with a valid leaf and a revoked intermediate fails revocation checking. Neither failure is visible from the leaf’s notAfter alone.

Does a successful verify mean the certificate is valid for my clients?

It means the chain validates against the trust store you gave it, at the time you ran it, with the revocation settings you configured. If your clients use a different trust store, a different revocation policy, or a different clock, the answer can differ. Probe with the configuration you actually care about.

The Element Tiles Don’t Spell It: Reading the ‘I Wear This Shirt Periodically’ Shirt

The shirt reads I WEAR THIS SHIRT PERIODICALLY, and beneath the sentence sit four tiles in the visual grammar of the periodic table: 53 I, 74 W, 22 Ti, 16 S. The symbols, read left to right, are I W Ti S. They are not a literal spelling of the sentence above them. That gap is the design’s actual argument, and it is worth more attention than the pun alone usually gets.

Most periodic-table jokes work by substitution. You take a word, find element symbols that approximate its letters, and let the reader do the decoding. The pleasure is in the click of recognition. This shirt does something slightly different. The sentence is already there, fully spelled out in ordinary letters. The tiles are not carrying the message; they are annotating it. The joke is not that the elements spell the sentence. The joke is that they almost do, and that the almost is the point.

What the tiles actually say

Read the tiles as a chemist would read them, symbol first, atomic number second. Iodine, tungsten, titanium, sulfur. Four elements, four symbols, four numbers. The symbols are I, W, Ti, S. Say them aloud and you get something close to “I wear this” — close enough that the eye wants to finish the sentence, and the sentence is already printed above to help it along. The design is not asking you to decode a hidden message. It is asking you to notice that the decoding is imperfect and that the imperfection is the joke.

This is a more interesting construction than a straight substitution cipher, because it depends on the reader holding two readings at once. The top line is a claim about the wearer’s habits. The bottom line is a chemical in-joke that only works if you know the symbols and also know they do not quite spell what you expect. The shirt rewards the reader who pauses. It punishes nobody who doesn’t. That is a reasonable design contract for a piece of clothing.

The word ‘periodically’ is doing two jobs

The adverb is the hinge. In ordinary English, “periodically” means from time to time, at intervals. In a chemistry context, it points at the periodic table, the arrangement of elements by atomic number and recurring properties. The shirt uses the word in both senses simultaneously, and the tiles underneath make the second sense visible. The sentence is not a chemistry claim. It is a scheduling claim that has been given a chemistry costume.

What I find worth noting is that the costume is not decorative. The tiles are specific. The numbers are real atomic numbers for those elements. The symbols are the actual symbols. The design has done the work of getting the chemistry right, then used that correctness to support a joke that is deliberately not a chemical statement. That is a different kind of care than a shirt that simply prints “Periodic Table” in a blocky font and calls it a day.

A slogan versus a usable promise

Technical readers spend a lot of time around slogans that are not promises. A status page that says “all systems operational” is a promise. A sticker that says “I break for kernel panics” is a slogan. The difference matters because slogans are cheap and promises are expensive. This shirt is firmly in the slogan category, and it is honest about that. It does not claim the wearer is a chemist, a scientist, or even particularly good at chemistry. It claims the wearer wears the shirt periodically, which is a modest and verifiable statement about laundry rotation.

That modesty is part of why the design works. The joke is not “I am a genius.” The joke is “I own a shirt and sometimes put it on.” The periodic-table tiles elevate a mundane admission into a small visual puzzle. The wearer is not asserting expertise. The wearer is asserting a schedule. In a work culture that often confuses visible enthusiasm with competence, a shirt that makes a smaller, more accurate claim is a quiet relief.

Reading the boundary between joke and claim

There is a temptation, when writing about a shirt like this, to inflate it into a statement about STEM education or the value of science communication. I do not think the artwork supports that. The design is a pun. It is a well-constructed pun with accurate element data, but it is not an argument about anything. The useful observation is narrower: the shirt distinguishes between a sentence that is spelled out and a set of symbols that almost spell it, and it lets the reader enjoy the gap. That is a specific visual move, and it is executed cleanly.

If you are the kind of person who reads config files for fun, you probably already know the difference between a message that is literally true and a message that is usefully true. This shirt is literally true in its top line and usefully funny in its bottom line. The two do not have to agree. The design knows that, and it does not try to force them together.

The shirt is available as a standard t-shirt from Quirky Cotton Collective: I Wear This Shirt Periodically Funny Chemistry Science Pun. The listing title and the observed artwork are the basis for everything above; I have not worn it, tested it, or surveyed anyone who has.

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

The Crossed-Out Hand Is the Whole Argument: Reading the ‘Not Friendly Do Not Touch’ Shirt

The shirt does not say stay away. It says NOT FRIENDLY in warning-sign capitals, then DO NOT TOUCH beneath it, with a yellow caution triangle and a hand crossed out by a diagonal bar. The crossed-out hand is the part I keep returning to. A hand is not a hazard in the way a wet floor or a high-voltage cabinet is a hazard. It is the ordinary instrument of greeting. The design borrows the grammar of industrial safety signage and points it at the most routine social gesture there is.

That is a more specific joke than the phrase “introvert shirt” suggests, and it is worth reading closely rather than filing under personality types.

What the sign language actually claims

Warning signs work because they compress a rule into a shape you can parse at a distance. Yellow triangle: caution. Diagonal bar over a pictogram: this action is prohibited. The format assumes a reader who is moving, possibly in a hurry, possibly not paying attention, and who needs the instruction before the situation develops. It is signage for people who will not read a paragraph.

Applied to a person, the format makes an odd but coherent claim. It says the boundary is not a mood or a preference to be negotiated in the moment. It is posted. It is legible from across a room. The wearer has done the social labor in advance so that no one has to discover the limit by crossing it.

I read the crossed-out hand as the design’s real content, not decoration. The words alone — not friendly, do not touch — could be mere grumbling. The pictogram converts grumbling into a posted rule. A hand reaching toward the wearer is the exact thing being prohibited, and the diagonal bar is the exact mechanism of prohibition. The shirt is not describing a personality. It is issuing an instruction in the only visual vocabulary that reliably survives being ignored.

The difference between a slogan and a usable promise

Most joke shirts are slogans. They assert something about the wearer and leave it there. This one is closer to a specification, and specifications are interesting because they can be evaluated.

A usable promise has three properties. It is stated in advance. It is unambiguous to a reader who has not been briefed. And it is enforceable by the person who posted it. The warning-sign format delivers the first two almost automatically. The third is where the design gets honest: a shirt cannot actually stop a hand. What it can do is remove the excuse. After the sign is read, a boundary crossed is a boundary crossed knowingly.

That is the same distinction I care about in operational writing. A runbook that says “monitor the service” is a slogan. A runbook that says “if queue_depth > 500 for five minutes, page the on-call and run this command” is a promise you can hold someone to. The difference is not tone. It is whether the statement tells a reader what to do when the situation arrives. The shirt’s lettering passes that test in the social register: it tells the reader what not to do, in advance, without requiring a conversation.

I am not claiming the design was conceived as a lesson in interface writing. I am saying the format it borrows is the format that works, and that is why the joke lands. Caution signage is one of the few visual systems most adults have already learned to obey without reading.

Why the terse version is the harder version

There is a temptation to read the shirt as antisocial. I think that misreads the mechanism. The blunt version is often the kinder one, because it replaces a slow accumulation of small signals — the closed posture, the one-word answers, the unanswered message — with a single legible statement. Ambiguity is not politeness. It is a cost transferred to the other person, who now has to guess.

The design’s economy is the point. Six words, one triangle, one barred pictogram. Nothing to interpret, nothing to negotiate. Whether that reads as hostile or as considerate depends on the reader’s position: a boundary that is never stated has to be inferred from a cold shoulder, and the posted version is easier to live with than the guesswork.

This is also why the shirt works better as an object than as a caption. A caption can be scrolled past. A sign on a chest is encountered at conversational distance, which is exactly the distance at which the rule applies.

Reading the object without overclaiming it

The listing is the Not Friendly Do Not Touch Funny Warning Sign Introvert shirt from Quirky Cotton Collective, observed live on the US marketplace on 14 October 2026 as a standard t-shirt. The visual observation is the one I have been working from: warning-sign lettering, a yellow caution triangle, and a crossed-out hand. I have not worn it, and I am not going to pretend a garment review is the right frame for a design this simple. What can be said is what the artwork does, and the artwork is unusually disciplined about doing one thing.

The restraint is worth naming. There is no second joke, no ironic sub-caption, no decorative clutter competing with the pictogram. A warning sign that hedges stops being a warning sign. The design trusts the format enough to leave it alone, and that trust is what makes the crossed-out hand read as a rule rather than a punchline.

If there is a criticism, it is that the format is so familiar it can be read too quickly — glanced at, categorized as novelty, and dismissed before the instruction registers. That is a risk inherent to borrowing signage grammar: familiarity is the source of its authority and also the reason people stop seeing it. The shirt’s best audience is the one that looks twice.

What the sign leaves out

A real caution sign usually tells you what to do instead. Authorized personnel only. Use alternate route. Keep clear. This one only prohibits. That omission is where the design is most honest about its limits: it can post a boundary, but it cannot supply the alternative. The wearer still has to be a person after the sign is read. The shirt handles the approach; it says nothing about what happens next.

I find that more interesting than a slogan would be. The crossed-out hand is not a claim that the wearer is difficult or dangerous. It is a claim that the terms of contact are posted, in advance, in a format no one can plausibly misunderstand. That is a small and specific promise, and the design keeps it.

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

The Notification and the Nose: Reading the Doorbell-Camera Cat Shirt

The shirt does not show a cat on a porch. It shows a notification, and then it shows what the notification is about. At the top, a white rounded banner with a small bell icon carries the sentence There is motion at your front door. Below it, inside a circular, green-tinted frame, an orange tabby stares into the lens from a distance of roughly nothing. Porch siding and a light fixture sit behind the cat’s head. The composition is a stack: message first, evidence second. That order is the joke, and it is also the most interesting thing about the design.

Most novelty shirts put the punchline in the text and let the image decorate it. This one inverts the usual hierarchy. The text is the kind of sentence a doorbell camera pushes to a phone — flat, procedural, almost bureaucratic. The image is the reason that sentence exists. Read top to bottom, the shirt performs the exact sequence a homeowner experiences: the alert arrives, you open it, and the cause of the alert is a cat with its face pressed against the camera housing. The banner is not a caption. It is the notification, and the circle is the attachment.

What the green circle is doing

The circular crop with a green cast is doing specific visual work. It reads as a camera feed rather than a photograph — the tint suggests night vision or a low-light sensor, and the circle suggests a fisheye lens or an app’s thumbnail view. The cat is not posed. It is too close, slightly distorted by the lens, eyes wide in the way that animal faces go wide when a small object makes a noise. The porch siding behind it is ordinary. The light is ordinary. Nothing about the scene is dramatic except the proximity.

That proximity is the whole point. A doorbell camera exists to answer a question: who is at the door? The answer here is nobody the system was designed for. The cat has defeated the sensor by being small, warm, and curious. The shirt does not need a caption explaining this. The banner says motion; the circle shows the motion; the viewer supplies the rest.

The sentence as a boundary

There is a useful distinction between a slogan and a usable message, and this shirt sits on the right side of it. There is motion at your front door is not a slogan. It is a status line. It tells you what happened, where it happened, and nothing else. It does not tell you whether to worry. It does not tell you who or what caused the motion. It is, in the literal sense, a notification: a terse, factual push from a system that has detected a change and is passing the observation to a human for judgment.

Anyone who has run monitoring knows this shape. A good alert says what fired and where. A bad alert says everything is fine until it isn’t. The doorbell banner is the good kind — short, specific, and honest about its own limits. It does not claim the cat is a burglar. It does not claim the porch is safe. It reports motion and stops. The humor comes from the gap between that restraint and the absurdity of the cause.

I like the shirt for that reason more than for the cat itself. The cat is funny. The sentence is well-built. It is the kind of message a careful operator would write: no adjectives, no speculation, no reassurance. Just the observation and the location. The fact that the observation turns out to be a tabby with its nose on the lens is the payoff, but the discipline of the wording is what makes the payoff land.

Why the stack matters

If the design were only the cat, it would be a cute animal shirt. If it were only the banner, it would be a generic tech-humor shirt. The combination is what makes it specific. The banner establishes the system’s point of view — automated, literal, slightly officious. The circle establishes the human’s point of view — the thing the system could not classify. The shirt is a small diagram of a mismatch between what a sensor reports and what a person sees.

That mismatch is familiar to anyone who has tuned an alert threshold. You set a rule, the rule fires, and the thing that triggered it is not the thing you were worried about. A cat on a porch is a harmless version of that experience. The shirt does not pretend it is a security lesson. It is a visual joke about a notification that was technically correct and practically useless, and it works because both halves of that sentence are visible at once.

The There Is Motion At Your Front Door shirt is a standard t-shirt from Quirky Cotton Collective. The design is the banner and the circular camera view, nothing more. It does not need more. The joke is complete in two elements, and the restraint is part of the appeal.

Reading it as an off-duty object

This is not a shirt that argues for self-hosting or against it. It is not a tutorial and it is not a policy statement. It is a piece of clothing that happens to use the visual grammar of a monitoring system to make a joke about a cat. That is a legitimate thing for a technical reader to enjoy. The vocabulary of alerts, thresholds, and status lines has leaked out of the terminal and into everyday objects, and this shirt is a clean example of that leak.

The design also has a practical virtue: it is legible. The banner text is short enough to read at a glance, and the circular image is distinct enough to register from across a room. A shirt like this works best when the joke arrives before the explanation. Here it does. You see the notification, you see the cat, you get it. The order is the message.

What I keep coming back to is the sentence itself. There is motion at your front door. It is a complete thought, delivered without drama, and it leaves the interpretation to whoever reads it. That is a good way to write an alert. It is also, apparently, a good way to write a shirt.

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

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.

Posts navigation

1 2 3 4
Scroll to top