The Loudest Possible ‘meh’: Reading the Typography of a Dismissive Word

The native garment preview shows large bold white lowercase meh. lettering on a dark shirt. No animal illustration is present. That is the whole design. Four letters, a period, and a lot of negative space.

What interests me is the mismatch. The word is a shrug. The typography is a shout. If you set meh in 11-point Helvetica on a white tee, you have made a shirt that apologizes for existing. Set it in heavy lowercase across a dark chest, and you have made a shirt that announces indifference at a volume that suggests the wearer is not indifferent at all.

That contradiction is the design. It is not a bug in the print file.

The period is doing the work

The period after meh is the smallest element in the artwork and the one I keep returning to. Without it, the word is a sound. With it, the word is a sentence. A sentence implies a speaker who has considered the matter and reached a conclusion. The conclusion is meh, but the grammar is declarative.

I have spent enough time reading error messages to recognize the pattern. The most alarming line in a log is rarely the one with the stack trace. It is the short, flat, punctuated line that follows: retry exhausted. giving up. The period is what makes it final. The shirt borrows that finality and applies it to nothing in particular.

Whether that reads as dry humor or as genuine fatigue depends entirely on the wearer and the room. The artwork does not resolve the ambiguity. It just supplies the punctuation.

Lowercase is a claim about effort

The lettering is lowercase, bold, and white on dark. Lowercase meh is not the same as MEH. Uppercase would be a complaint, or a meme, or a brand. Lowercase is a posture: the word has been typed without reaching for the shift key. The bold weight contradicts the lowercase informality, which is the second small joke in the design.

I read this as a visual argument about effort. The shirt is not saying the wearer cannot be bothered. It is saying the wearer has calibrated their bother. There is a difference between laziness and triage, and the lowercase bold treatment sits right on the line between them.

That is an interpretation of the typography, not a claim about the shirt’s history or intent. The artwork shows what it shows: large, bold, white, lowercase, punctuated. Everything else is reading.

Why this works better than a longer slogan

Most sarcastic shirts fail because they explain the joke. They give you a setup, a punchline, and a font choice that says this is the punchline. The meh. shirt does none of that. It gives you a word that is already a verdict and trusts you to supply the context.

For a technical audience, that restraint is the appeal. We spend our days reading messages that are too long, too hedged, and too eager to be helpful. A shirt that says one word and then stops is a small relief. It is the visual equivalent of a well-named variable: short, unambiguous, and not trying to be your friend.

The design is available as a standard t-shirt through the listing at https://www.amazon.com/dp/B0FXT2SFW3. The native preview shows the dark-shirt version with white lettering; the listing is the authoritative source for available colors and sizes.

The maintenance burden of a one-word shirt

Every object carries a cost, and this one is social rather than operational. A shirt that says meh. in large bold type invites a specific question: meh about what? The wearer has to decide, in real time, whether to answer honestly, deflect, or lean into the bit. That is a small ongoing tax, paid at every interaction.

The alternative — a longer, more specific slogan — pays a different tax. It explains itself once and then has nothing left to say. The meh. shirt stays ambiguous, which means it stays usable, which means the wearer keeps having to manage the ambiguity. That is the tradeoff. The design is efficient. The conversations it starts are not.

I think that is the right trade for an off-duty shirt. It is a low-stakes object with a high-contrast design, and it does not pretend to be more than that. The period is the only promise it makes: this is the end of the sentence. Whether the wearer means it is their problem.

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

The Consumer Was Down for Eleven Days and the Topic Retains Seven: Rebuilding the Offset Gap That Kafka Retention Silently Ate

The Consumer Was Down for Eleven Days and the Topic Retains Seven: Rebuilding the Offset Gap That Kafka Retention Silently Ate

Eleven days down. Seven days retained. The arithmetic is the whole incident, and it is not a Kafka problem. It is an offset-gap problem, and the gap is permanent the moment the committed offset falls below the partition’s low watermark.

This article is about that moment: how to detect it in one query, how to tell it apart from a silent rewind that looks identical on a lag graph, and how to price the rebuild honestly. The eleven-and-seven numbers are the scenario, not a case record. The mechanics below are documented and reproducible on your own cluster.

The failure signature is a vertical line, not a slope

A slow consumer produces a backlog that ramps up at a finite slope. A consumer that has lost its position produces a near-instant jump to multi-day lag. The Karafka documentation on offset rewind states the distinction plainly: a near-instant jump to multi-day lag is only physically possible if the consumer’s offset pointer has been moved backward to an older position.

When the consumer restarts after eleven days, it asks the broker for its committed offset. The broker answers with offset_out_of_range because that offset has been trimmed. The client then applies auto.offset.reset. If that setting is earliest — the common default in many client configurations — the consumer silently seeks to the oldest retained offset and begins consuming from there. The lag graph shows a vertical rise to the retention ceiling, then a slow drain. Nothing pages. Nothing errors. The pipeline is now missing four days of events and will never know unless someone checks.

The Karafka documentation describes this exact path as expected behavior, not a bug: consumer downtime longer than the retention window causes Kafka to legitimately return offset_out_of_range, and the client resets to earliest.

Retention is a property of the log, not a promise about your position

The default cleanup policy is delete, which discards old log segments once their retention time or size limit is reached, per the Confluent topic configuration reference. The default retention is 168 hours, or seven days, per Confluent’s retention guide. Both can be overridden per topic with kafka-configs.sh --alter --entity-type topics --entity-name <topic> --add-config retention.ms=....

Two mechanics make “seven days retained” a weaker guarantee than it sounds.

First, deletion happens at segment granularity. A message past its retention age is not removed until its entire segment is eligible. The AutoMQ retention wiki puts it directly: when a message’s age exceeds the configured retention period, the entire segment containing that message becomes eligible for deletion, but only if all messages within that segment have also exceeded the threshold. The active segment is never cleaned up regardless of retention settings. So the actual earliest available offset is a function of segment.ms, segment.bytes, and write rate — not just retention.ms.

Second, retention and offset retention are two separate clocks. A consumer group inactive beyond offsets.retention.minutes (default seven days, per the AutoMQ wiki) loses its committed offsets entirely. When it reactivates, it has no position to fall back to and starts from auto.offset.reset. This failure mode looks identical on the lag graph but has a much cheaper fix: the messages are still in the log, and the position can be reconstructed from a known timestamp or a downstream checkpoint.

An eleven-day outage can trip both clocks. That is why the first diagnostic question is not “why did the consumer stop” but “did the offset move backward, or did the log move forward past it.”

One query classifies the failure

When offset_out_of_range appears, the broker includes the partition’s low and high watermarks alongside the requested offset. The comparison tells you which sub-case you are in.

  • Requested offset below the low watermark: the consumer’s position is below the oldest retained offset. This is a genuine retention overrun or a client-side rewind. The front of the log is gone.
  • Requested offset above the high watermark: the committed offset is ahead of the log end. This indicates broker-side data loss — unclean leader election, log truncation. Investigate broker log integrity before anything else.

You can reproduce the watermark check without waiting for an error. Use kafka-consumer-groups.sh --describe to get the group’s committed offset per partition, and kafka-get-offsets.sh (or GetOffsetShell) to get the earliest and latest offsets. If the committed offset is less than the earliest offset, the gap is real and no retention setting recovers it.

Before running any reset, note the operational constraint: resetting consumer offsets requires first emptying the consumer group by stopping its clients or consumers, per the Confluent Cloud offset-reset documentation. A reset against a live group either fails or produces undefined behavior. Plan the stop window.

Two paths to the same graph, two different fixes

The lag graph cannot distinguish a retention overrun from a silent rewind. The watermark check can, and the fix differs by an order of magnitude in cost.

Retention overrun. The consumer was down longer than the topic retains. The missing window must be rebuilt from upstream. Kafka has nothing to give you.

Silent rewind. The consumer’s offset moved backward while the messages were still in the log. The Karafka documentation catalogs the known causes: librdkafka cooperative-sticky bugs below 2.4.0, broker-side segment races in Kafka versions before 0.10.0 and in 2.4.0–2.5.0, and manual operator resets. The distinguishing signal is timing: rewind bugs correlate with rebalance events or segment rolls, not with the consumer’s downtime. If the consumer was up and the lag still spiked to the retention ceiling, you are debugging a client or broker bug, not paying for a backfill.

This distinction matters because the rewind case is cheap. Seek the group to the correct position and replay. The overrun case is expensive. You are about to reconstruct days of change data from a source system that may not have a clean snapshot boundary.

Price the gap in reconciliation work, not in Kafka terms

The cost of a retention overrun scales with the number of downstream tables that consumed the topic, not with the topic’s size. A CDC topic feeding one warehouse table is a different job from the same topic feeding forty dbt models across three marts.

Consider an illustrative case — hypothetical, not a recorded incident. A CDC topic with seven-day retention feeds a warehouse. The consumer is down eleven days. Four days of messages are gone. The recovery has two parts:

  1. Snapshot at the retention boundary. Take a consistent snapshot of the source tables as of day seven, the last point Kafka can still replay from. This is a source-system operation, not a Kafka one. Its cost is the snapshot size and the lock or replication-slot overhead it imposes on the source.
  2. Replay days seven through eleven from Kafka. This is the part Kafka can still do. It requires the consumer to start from the earliest retained offset and apply events idempotently, because the snapshot and the replay will overlap at the boundary.

Then reconcile. Count rows and distinct keys per table between the rebuilt warehouse state and the source. Any mismatch is either a missed event or a duplicate applied twice. The reconciliation query is cheap to write and expensive to run at scale, and it is the only honest proof that the gap is closed.

The on-call hours are dominated by the snapshot coordination and the reconciliation, not by the Kafka replay. Budget accordingly.

The upstream side has its own retention clock

If the topic is fed by Postgres logical decoding, the outage did not only affect Kafka. A replication slot persists across crashes and knows nothing about the state of its consumer, per the PostgreSQL logical decoding documentation. It will prevent removal of required WAL even when no client is connected. An eleven-day consumer outage means eleven days of WAL retained on the primary, and in extreme cases the database can shut down to prevent transaction ID wraparound.

This changes the recovery plan. You cannot simply restart the CDC connector and expect it to resume from where it stopped if the slot was dropped to reclaim disk. And if the slot was not dropped, the WAL volume is the first thing to check before you add replay load.

The PostgreSQL documentation also notes that a slot’s position is persisted only at checkpoint, so after a crash it may return to an earlier LSN and resend recent changes. Any replay path must be idempotent on the consumer side. This is not optional hygiene; it is a documented behavior of the slot.

A recovery runbook that does not pretend the gap is smaller than it is

The sequence below assumes a confirmed retention overrun: committed offset below the low watermark, messages gone. Adjust if the watermark check says otherwise.

1. Stop the silent reset. Set auto.offset.reset=error on the consumer before restarting it. This converts a silent seek-to-earliest into a stopped partition with a raised error. The Karafka documentation is explicit that this is a diagnostic and a guard, not a mitigation: it only fires when the consumer has no valid position to fall back to. It does not preserve a position, because there is none to preserve. Do not enable it without alerting on the resulting error and a runbook to seek the partition, or the guard becomes the outage.

2. Record the watermarks. Capture the committed offset, the low watermark, and the high watermark per partition before any reset. This is the evidence that classifies the failure and the baseline for reconciliation.

3. Empty the group. Stop all consumers in the group. Offset reset requires an inactive group, per the Confluent Cloud documentation. For groups using manual assign(), locate and pause the assigning consumer — such groups appear empty in tooling but may hide running consumers.

4. Seek to the earliest retained offset. Reset the group to earliest. This is the start of the replayable window, not the start of the gap. The gap is everything before it.

5. Snapshot the source at the boundary. Take a consistent snapshot of the upstream tables as of the timestamp corresponding to the earliest retained offset. This is the expensive step. Its duration depends on source size and the snapshot mechanism available.

6. Replay and apply idempotently. Consume from earliest with deduplication on a stable key. The snapshot and the replay overlap at the boundary; the consumer must tolerate seeing the same change twice.

7. Reconcile. Compare row counts and distinct keys per downstream table against the source. Document any residual gap explicitly. An undocumented gap is worse than a documented one.

What the guard costs and what it does not buy

auto.offset.reset=error is the cheapest change in this article and the one most likely to be deployed without its companion. Alone, it converts silent data loss into a stopped partition. That is a better failure mode, but it is still a failure. The companion is an alert on the offset-reset error and a runbook that tells the on-call engineer which partitions to seek and to what position. Without that, the guard pages someone at 3 a.m. with no action to take.

The setting does not prevent retention overrun. It does not extend the replay window. It does not recover the gap. It only makes the gap visible at the moment it happens instead of weeks later during a reconciliation that does not tie out.

The maintenance tax is in the configuration, not the incident

Retention settings, offset retention, and rebalance behavior are configuration decisions that determine whether an outage is a two-hour catch-up or an eleven-day rebuild. They are usually set once, at topic creation, and never revisited.

Three checks are worth running before the next outage, not after.

Compare retention to realistic downtime. If the topic retains seven days and the consumer has no documented recovery-time objective shorter than that, the retention window is a guess. The default is 168 hours because it is a default, not because it matches your recovery posture.

Check offsets.retention.minutes separately. A consumer down past the offset-retention window loses its position even if the messages are still in the log. That failure is cheaper to fix but looks identical on the graph. Knowing which clock expired first saves hours.

Know your rebalance behavior. If the client library is librdkafka below 2.4.0 and uses cooperative-sticky assignment, the rewind bug is a live possibility. The Karafka documentation notes that switching to an eager assignor eliminates the implicit-resume path, at the cost of pausing the entire group on every rebalance. That is a tradeoff, not a fix. The fix is the upgrade.

None of these checks prevents an eleven-day outage. They determine whether the recovery is a replay or a rebuild. That is the maintenance tax: the work you do before the incident decides which invoice you pay after it.

FAQ

Does increasing retention now recover the missing days? No. Retention governs future deletion. Messages already deleted are gone. Increasing retention.ms changes the window for events written from now on, not for events written eleven days ago.

Can I reset the offset to a timestamp instead of earliest? Yes, kafka-consumer-groups.sh --reset-offsets --to-datetime seeks to the nearest offset at or after a timestamp. But if the timestamp falls before the earliest retained offset, the reset lands at earliest anyway. The watermark check tells you whether the timestamp is inside the replayable window.

Why did the consumer not error when it reset? Because auto.offset.reset defaults to a silent seek in many client configurations. The broker returned offset_out_of_range; the client handled it by seeking. Setting the value to error changes the client’s response, not the broker’s.

Is tiered or remote storage a fix? It changes the economics of long retention by moving old segments off broker-local disk, but it does not change the offset-gap mechanics. If the committed offset is below the low watermark of the tiered log, the gap is still a gap. Tiering extends the window; it does not guarantee your consumer’s position is inside it.

How do I know the rebuild is complete? Row counts and distinct keys per downstream table match the source at the reconciliation timestamp. Anything short of that is a documented gap, not a recovery.

The Caution Triangle That Says Nothing About the Hazard: Reading the ‘Not Friendly Do Not Touch’ Warning Sign

The first thing I notice is the triangle. Yellow, equilateral, the universal shape for something here can hurt you. Inside it, a hand with a slash through it. Above and below, in the blocky lettering of a municipal sign, the words NOT FRIENDLY and DO NOT TOUCH.

It is a warning sign with no hazard named. That is the interesting problem. Real caution signs are load-bearing: they tell you what the danger is, where it is, and what to do about it. This one borrows the entire visual grammar of safety signage and then spends it on a mood. The hazard is a person. The mitigation is distance. The sign does not say why.

I have spent a lot of my working life reading error messages, and the ones that waste the most time are the ones shaped like this: authoritative, formatted, and missing the one field that would let you act. ERROR: operation failed is a caution triangle with no hazard. You know something is wrong. You do not know what to do.

The sign is honest about the wrong thing

Look at what the artwork actually commits to. The crossed-out hand is a prohibition, not a description. It does not say I am tired or I am busy or I am shy. It says: do not touch. That is a boundary with a clear verb and a clear object. Whatever the wearer means by it, the shirt is not asking you to infer their interior state. It is telling you what to do with your hands.

That is a more usable message than most workplace communication I have sat through. Compare it to the standard office phrasing: let’s circle back, I have a lot on my plate right now, can we take this offline. Each of those is a caution triangle with the hazard filed off. You are left to guess whether the person is annoyed, overloaded, or simply not interested. The shirt, for all its bluntness, does not leave you guessing about the action item.

I would rather get a crossed-out hand than a paragraph of hedged availability. The crossed-out hand is a contract. The paragraph is a negotiation you did not agree to.

What the caution triangle borrows, and what it gives up

The yellow triangle is doing real semiotic work. It is the same shape you see on a wet-floor sign, a high-voltage cabinet, a forklift. It signals this is not decorative. By putting a person behind it, the design makes a small joke about how we classify other people: as conditions to be managed, hazards to be routed around.

That joke only lands because the triangle is so recognizable. Strip the triangle and you have three words in a font. Keep the triangle and you have a visual pun that reads instantly across a room, which is the only distance at which a t-shirt message ever actually functions. Nobody reads the fine print on a chest. They read the shape and the first three words.

What the design gives up is specificity. A real warning sign would name the hazard. This one refuses, and that refusal is the whole point. The wearer is not obligated to explain themselves to a stranger in a grocery aisle. The sign says trust the boundary, not the biography. I find that more respectful than the alternative, which is a shirt that overshares in order to be understood.

The difference between a slogan and a usable promise

This is where the artwork connects to something I care about professionally, without pretending it is a lesson about software. A slogan is a sentence that sounds like a commitment. A usable promise is one you can act on when it fails.

Not friendly is a slogan. It is a self-description, and self-descriptions are unfalsifiable. Do not touch is closer to a promise: it has a trigger, an action, and a clear owner. If you touch, you have violated a stated term. The shirt does not need to explain why the term exists. It only needs to state it plainly enough that a reasonable person can comply.

Most of the bad interfaces I have maintained failed at exactly this distinction. They described themselves confidently and then gave you no way to know when you had crossed a line. The shirt, at least, puts the line on the front where you can see it coming.

There is a limit to the analogy, and I want to be honest about it. A t-shirt cannot enforce anything. It is a signal, not a control. The crossed-out hand does not stop a hand. It only makes the subsequent conversation shorter, and only if the other person is willing to read. That is a lower bar than a real safety system, and the design knows it. The humor comes from the gap between the authority of the format and the modesty of what it can actually deliver.

Who the sign is for, and who it is about

The retail title calls this an introvert shirt, and the keyword people search is the not friendly do not touch shirt. I understand the shorthand, but I think the design is slightly smarter than the label. Introversion is a preference for lower stimulation. This sign is not about stimulation. It is about consent. It is a portable no for anyone who is tired of being touched, hugged, tapped, or otherwise handled without being asked.

That is a broader category than introverts, and a more useful one. The sign does not require the wearer to be shy. It requires them to be done. Done with the hand on the shoulder, the lean-in, the assumption that physical familiarity is a default rather than a request. The crossed-out hand is not a personality type. It is a policy.

I like that the design does not soften the policy with a smiley face or an except for hugs asterisk. It commits. The commitment is what makes it readable, and readability is the only thing a chest-sized sign has going for it.

The maintenance burden of a blunt sign

Every clear boundary creates a new job for someone. The shirt says do not touch, which means the wearer now owns the follow-through: the awkward pause, the explanation to the person who did not read, the decision about whether to enforce the sign or let it slide. A vague shirt would have spared them that. A clear one does not.

That is the tradeoff the artwork makes, and it is the same tradeoff I make every time I replace a hedged error message with a specific one. The specific message is more useful and more work. It tells the reader exactly what went wrong, which means the reader can now hold you to it. The vague message protects the author. The clear one protects the user and burdens the author.

The shirt chooses the user. I respect that, even as I recognize the cost it pushes onto the person wearing it. A warning sign is a promise to be inconvenient later.

Reading it as an object

The design is available on a standard t-shirt from Quirky Cotton Collective, and the listing is here. I am not going to tell you it is soft, or that it fits well, or that strangers compliment it. I have not worn it. What I can tell you is what the artwork does: it takes the most authoritative visual format in public life and points it at the smallest, most personal boundary. The joke is the mismatch. The argument is that the boundary deserves the format.

If you are the kind of person who has ever written a Slack status that said heads down, please don’t ping and then felt guilty about it, the shirt is a lower-effort version of the same message. It does not require you to explain yourself. It requires you to accept that some people will read it and some will not, and that the ones who do are the ones you were writing for.

The caution triangle is empty because the hazard is not the wearer’s job to specify. The crossed-out hand is the whole contract. Everything else is commentary, including this column.

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

The Period After ‘meh’: Reading the Smallest Possible Slogan

The native garment preview shows four lowercase letters and a period, centered on a dark shirt, at a size that would fit inside a thumbnail. meh. That is the whole design. No animal, no pride variant, no secondary line of copy. The period is doing more work than the letters.

I want to argue something specific about this object: the period is what turns a shrug into a boundary. Without it, meh is a mood. With it, meh. is a complete sentence, and a complete sentence is a decision.

What the artwork actually contains

Observed directly from the listing’s native garment preview: very small, centered lowercase lettering reading meh. on a dark shirt. The retail title stacks up adjectives — funny, sarcastic, introvert, minimalist — but the printed artwork is just those four letters and the punctuation. The adjectives describe a category of buyer, not the design. The design is the design.

I am reading the scale and the period as deliberate. I have no evidence about the designer’s intent, and I am not going to invent any. What I can say is what the image shows: the word is small enough that a reader has to be close to resolve it, and the period is present and visible at that scale. That combination is unusual in slogan apparel, where the convention is large type and no terminal punctuation.

Why the period changes the register

In running prose, meh is an interjection. It trails off. It invites the other person to keep talking. Meh. with a period is declarative. It closes the exchange. The same four letters, one keystroke apart, produce opposite social instructions.

This is the same distinction engineers make between a log line and an alert. A log line says something happened. An alert says something happened and you are now responsible for it. The period is the page. The word without it is the log.

That is why the small type matters as much as the punctuation. A large MEH. across the chest is a performance — it announces the wearer’s attitude to the room. A small meh. at sternum height is only legible at conversational distance, which means it is addressed to one person at a time. The scale enforces the same thing the period does: this is a message for you specifically, and it is finished.

The difference between a slogan and a usable promise

Most work-culture shirts fail because they promise something the wearer cannot deliver. I’m not a robot is a claim about internal state. Sorry I’m late is an admission that invites a response. These are slogans: they start conversations the wearer may not want to have.

meh. is closer to a usable promise, because it is small enough and final enough to be true. It does not claim enthusiasm. It does not claim hostility. It sets an expectation the wearer can actually meet on a Tuesday. In operational terms, it is a service-level objective with a low target and no penalty clause — the only kind most teams can honestly commit to.

I would not push the analogy further than that. The shirt does not demonstrate anything about reliability engineering, and I am not going to pretend a garment is a runbook. But the design logic is legible to anyone who has written a status page: understate, punctuate, stop.

The introvert adjective and the small type

The retail title calls it an introvert shirt. I am skeptical of that framing as a factual claim about the wearer, but the visual argument is coherent. Small type rewards proximity and punishes distance. A person across the room cannot read it. A person at the next desk can. That is a design that selects its audience by geometry rather than by declaration.

Whether that constitutes introversion is a matter of interpretation, not measurement. What I can observe is that the shirt does not perform for a crowd. It performs for a radius of about three feet. That is a real design decision, and it is the opposite of how most slogan apparel works.

What the object is and is not

The shirt is available as a standard t-shirt through the listing at https://www.amazon.com/dp/B0FXC6KKSR. The artwork is the small centered lowercase meh. on a dark ground. There is no animal illustration and no pride variant in the preview. I have not worn it, and I am not going to describe how it fits.

The useful thing about the design is that it is honest about its own limits. It is a small word with a full stop. It does not promise a personality, a politics, or a productivity gain. It promises that the sentence is over. For a certain kind of engineer, that is the most credible claim a shirt can make.

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

The Doorbell Alert That Never Says Who’s There: Reading the ‘There Is Motion At Your Front Door’ Cat Shirt

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

The notification banner is the first thing you read, and it is almost aggressively unhelpful. A white rounded rectangle, a small bell icon at the left, and the sentence: There is motion at your front door. No name. No timestamp. No thumbnail. No confidence score. Just the bare assertion that something moved, delivered with the flat certainty of a system that has done exactly what it was asked and nothing more.

Below the banner, inside a circular frame tinted green, an orange tabby fills the lens. Its eyes are wide, its face is pressed close enough that the porch siding and lights behind it are mostly context. The cat is the motion. The cat is also the entire answer to the question the banner declined to ask.

That gap between the message and the image is the joke, and it is a better joke than most shirt slogans manage. The banner is technically correct. The camera did detect motion. The system did its job. But the sentence stops one step short of the thing a human actually wants to know, and the circular viewport below supplies it in the least dignified way possible.

What the artwork actually shows

The design is built from two stacked elements. The upper element is a notification banner: white, rounded corners, a bell glyph, and the sentence set in a clean sans-serif. The lower element is a circular doorbell-camera view, green-tinted the way cheap night-vision or compressed video feeds tend to look, with an orange tabby staring directly into the lens. Behind the cat, the porch reads as siding and a light fixture. The composition is tight; the cat’s face occupies most of the circle.

I read the green tint as a deliberate reference to the look of a doorbell camera at night or in low light. That is an interpretation of the visual language, not a claim about how any specific camera model renders color. What is observable is the tint, the circle, and the extreme close-up. The cat is not sitting politely on a mat. It is investigating the device that is watching it, which is a very cat thing to do and also the reason the image works.

The wording is the common doorbell-alert phrase. The shirt does not add a punchline underneath it. It does not need to. The punchline is the face.

The slogan is a promise the system can’t keep

Most novelty shirts rely on a sentence that is funny by itself. This one relies on a sentence that is funny because of what it omits. There is motion at your front door is a complete, grammatically tidy, operationally useless message. It tells you a threshold was crossed. It does not tell you whether the motion was a delivery, a raccoon, a gust of wind, or a cat attempting to reverse-engineer the sensor.

Anyone who has spent time around monitoring systems recognizes the shape of that message. It is the alert that fires on the condition rather than the consequence. The dashboard is green. The event count is nonzero. The on-call engineer still has to open the thing and look, because the notification was never designed to answer the question that actually matters.

I am not going to pretend the shirt is making a point about observability, and I am not going to claim the designer had alert fatigue in mind. The design is a cat meme. But the reason the meme lands is that the sentence is a familiar kind of incomplete. It is the same incompleteness that makes a bare motion detected event feel like a small insult at 2 a.m. The system knows something happened. It has declined to say what.

Why the circular frame does the work

The banner alone would be a mildly funny sentence. The circle below it is what turns the sentence into a scene. A doorbell camera view is a specific visual genre: fisheye distortion, a greenish cast, a subject who is either too far away to identify or, as here, far too close. The circular crop is not decorative. It signals this is what the camera saw, and the camera saw a cat’s face at point-blank range.

The cat’s expression is the second half of the joke. Wide eyes, ears slightly back, nose nearly touching the glass. It is the look of a creature that has noticed it is being watched and has decided to investigate the watcher. The porch behind it is ordinary. The lighting is ordinary. The only extraordinary thing in the frame is the cat, and the cat is the reason the alert fired.

There is a small structural pleasure in the way the two elements are stacked. The banner is the system’s summary. The circle is the raw evidence. The shirt puts them in the order a person actually experiences them: first the useless notification, then the look at the feed, then the sigh.

What the shirt is not

It is not a product review, and I am not going to describe how it fits or wears. The listing is for a standard t-shirt, and the artwork is what I can actually observe. The design is printed as described: banner, bell, sentence, circular green-tinted cat view. The retail title calls it a funny cat doorbell meme, and that is an accurate description of the visual content.

It is also not evidence of anything about doorbell cameras, cats, or the people who buy either. The shirt does not cure anything, improve anything, or demonstrate a security outcome. It is a joke about a message that stops short, and the joke works because the image picks up where the message stops.

If you are looking for the object itself, the listing is here: There Is Motion At Your Front Door Funny Cat Doorbell Meme.

The maintenance burden of a terse message

The reason this design keeps working after the first look is that the gap it depicts is a real and recurring one. A notification that reports a condition without context is cheap to build and expensive to live with. Every recipient has to do the interpretation manually. In a doorbell camera, that means opening the app. In a production system, it means opening a dashboard, a log, or a query. The message did not save anyone work. It moved the work downstream.

That is the tradeoff the shirt accidentally illustrates. Terse alerts are easy to emit and hard to act on. Rich alerts cost more to construct and less to receive. The cat, pressed against the lens, is the downstream cost made visible: the thing you have to look at because the sentence would not tell you.

There is no fix printed on the shirt, and I am not going to invent one. The design’s argument is simply that the banner and the cat belong together, and that the banner alone would be a worse shirt. The new burden it creates is the same one the original alert created: you have to look at the picture to understand the message. Fortunately, the picture is the best part.

The Ball at the Bottom of the Ramp: Reading the ‘I Had Potential’ Physics Diagram

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

Most readings of this shirt stop at the words. The joke seems obvious enough: a person announcing that their potential has been spent, phrased in the vocabulary of a physics problem. But the drawing is doing more work than the caption, and the drawing is where the design either holds together or falls apart. I think it holds together, but only if you read the dashed circle and the solid ball as two different states of the same object rather than as decoration.

Here is the argument. The shirt is not a slogan about wasted talent. It is a diagram of a system that converted potential energy into kinetic energy and then stopped, and the joke depends on the reader recognizing that the stop was the point. The dashed circle is where the ball was. The solid ball is where it is. The ramp is the path between them. Nothing in the drawing says the ball failed to reach the bottom. It reached the bottom. That is the punchline, and it is a more precise joke than the words alone would suggest.

What the dashed circle is actually saying

In physics diagrams, a dashed outline usually marks a position that is no longer occupied, or a boundary that is not a physical surface. Here the dashed circle sits at the upper left ledge, at the top of the ramp. The solid ball sits at the lower right, on the flat. The most natural reading is that the dashed circle is the ball’s starting position and the solid ball is its current position. The ball has rolled down.

That reading matters because it changes the tense of the sentence. “I had potential” is past tense, and the drawing agrees: the potential was at the top; the ball is now at the bottom. The shirt is not saying the potential was never real. It is saying the potential was real, was located somewhere specific, and has been converted. The dashed circle is the evidence. If the designer had wanted to say the potential was imaginary, the circle at the top would have been solid and the ball at the bottom would have been missing. Instead the empty position is at the top and the occupied position is at the bottom. The design is telling you the ball did the thing.

I am reading the drawing, not claiming the designer wrote a physics proof. The visual convention of a dashed outline for a prior or non-physical position is common enough in textbook diagrams that a reader who has taken a mechanics course will recognize it. Whether the designer intended that convention is not something I can verify from the garment image. What I can say is that the drawing is legible that way, and that legibility is what makes the shirt work as more than a caption.

The curved ramp is not a straight line, and that is the design’s best decision

A straight diagonal would have been the lazy choice. A ball on a straight incline is a first-week physics problem: constant acceleration, clean equations, no ambiguity. The curved ramp is harder to read and more interesting. A curved descending ramp suggests a path whose slope changes, which means the ball’s acceleration is not constant. The ball speeds up and slows down depending on where it is on the curve. That is a more realistic picture of how potential gets spent, and it is a better metaphor for a career than a straight slide.

I want to be careful here. I am not claiming the curve is a specific mathematical function or that the designer solved a differential equation. The curve is a drawing. But the choice of a curve over a straight line is a choice, and it produces a different feeling. A straight ramp reads as a controlled experiment. A curved ramp reads as a path with a shape, which is closer to how people describe their own trajectories: a few fast years, a plateau, a drop, a flat stretch at the bottom. The flat ledge at the lower right is part of that. The ball is not still moving. It is resting. The curve delivered it to a place where it stops.

That flat ledge is easy to overlook. The eye goes to the words and then to the ball, and the ledge reads as the edge of the design. But the ledge is where the joke lands. A ball at the bottom of a ramp that ends in a wall would be a different shirt. A ball at the bottom of a ramp that ends in a flat run-out is a ball that has finished. The design says: the motion is over, and the ending is level, not catastrophic. That is a drier joke than a crash, and a more accurate one for anyone who has watched a promising project settle into maintenance.

Why the words and the drawing need each other

Take away the drawing and you have a familiar sentence. “I had potential” is the kind of line that appears on a thousand shirts, usually with a skull or a cartoon or a bottle. It is a self-deprecating slogan, and self-deprecating slogans are cheap because they ask for nothing from the reader. You laugh, or you don’t, and the shirt is done.

Take away the words and you have a physics diagram with no caption. It could be a textbook illustration, a logo for a tutoring service, or a warning about a slippery floor. The drawing alone does not say anything about a person. It is the combination that produces the joke, and the combination is specific: the words supply the self-description, and the drawing supplies the mechanism. The shirt is funny because it treats a life outcome as a solved problem in mechanics. The ball did not fail. The ball converted its potential and came to rest. The sentence is the ball’s own summary of the event.

This is why the minimalist treatment matters. The design uses white on the garment, capitals for the words, and a simple two-object diagram with no labels, no axes, no numbers. There is no equation, no unit, no arrow. The absence of labels is what lets the drawing be a joke instead of a homework problem. If the ramp had a height marked h and the ball had a mass marked m, the shirt would be a physics pun for physics people. Without labels, it is a diagram that anyone who has seen a ramp can read, and the physics vocabulary is available but not required.

The difference between a slogan and a usable promise

The shirt is a work-culture object, and the reason it lands is that it describes a pattern technical readers see often: a system or a person arrives with a stated capacity, does the expected conversion, and then sits at the bottom of the curve in a steady state that nobody planned for. The potential was real. The conversion happened. The resting state is the surprise.

I am not going to pretend the shirt is a lesson in capacity planning. It is a drawing on a garment. But the drawing is precise about one thing that slogans usually get wrong: it separates the existence of potential from the outcome of using it. The dashed circle at the top is not a promise that was broken. It is a position that was occupied. The solid ball at the bottom is not a failure. It is the same object after the conversion. The shirt’s joke is that both statements are true at once, and the drawing is what makes them true at once.

That is a more useful piece of visual rhetoric than the words alone. A slogan says I had potential and asks you to supply the disappointment. A diagram says here is where the potential was, here is where the object is now, here is the path between them, and lets you supply the judgment. The second version is harder to argue with, because it shows its work. You can look at the dashed circle and the solid ball and decide for yourself whether the outcome is sad, funny, or just accurate. The shirt does not decide for you. It just draws the system.

What the shirt is not saying

It is worth being explicit about the claims the design does not make. The drawing does not show a ball that failed to roll. It does not show a broken ramp, a missing ball, or a ball stuck at the top. The dashed circle is empty because the ball left, not because the ball never arrived. The solid ball is at the bottom because the ramp worked. If you read the shirt as a complaint about wasted ability, you are reading the words and ignoring the drawing. The drawing is more generous than that. It says the conversion happened.

Nor does the shirt make a claim about physics that a physicist would need to check. It is a cartoon of a ramp and a ball, not a free-body diagram. There are no forces drawn, no vectors, no friction coefficient. The curve is a shape, not a plotted trajectory. I am reading the visual conventions, not asserting that the design is physically accurate in any technical sense. The joke does not depend on accuracy. It depends on recognition: the reader has seen a ball on a ramp, knows what happens to it, and recognizes that the shirt is using that knowledge to say something about a person.

The shirt also does not specify whose potential is in question. The sentence is first person, but the drawing is generic. That gap is part of the design’s flexibility. The shirt can be read as self-deprecating, as a comment on a colleague, or as a general observation about how things settle. The minimalist treatment keeps it from committing to a tone. There is no skull, no cartoon face, no bottle. There is a ramp and a ball and a sentence, and the reader supplies the rest.

Reading the object as an object

The shirt is sold as the I Had Potential Funny Physics Pun Sarcastic Minimalist Quote by Quirky Cotton Collective. The retail title uses the words “physics pun” and “sarcastic” and “minimalist,” and the design supports all three, though not in the way the title’s word order suggests. The pun is not in the words. The words are plain. The pun is in the relationship between the words and the drawing: the sentence describes a state, and the diagram shows the mechanism that produced it. The sarcasm is in the flatness of the ledge. The minimalism is in the absence of labels and the use of a single color.

I have not worn the shirt and I am not reviewing its fabric, fit, or print quality. What I can read is the artwork as observed: white capitals, a white curved ramp, a dashed empty circle at the upper left, a solid white ball at the lower right, a flat ledge. Those are the elements, and they are enough to support the argument. The design is not complicated, and it does not need to be. The joke is in the arrangement, and the arrangement is clear.

The one thing I would watch for as a reader is the temptation to over-read the curve. A curved ramp can suggest a lot of things: a learning curve, a career arc, a decay function, a rollout that slowed down. The shirt does not specify which. That is a strength, but it is also a limit. The design gives you a mechanism and a mood, not a thesis. If you want a shirt that makes a specific argument about a specific system, this is not it. If you want a shirt that draws a small, legible picture of conversion and rest, and lets the sentence do the talking, this is a clean version of that.

The maintenance burden of a good diagram

There is a cost to reading a design this closely, and it is the same cost that comes with any good diagram: once you have seen the mechanism, you cannot unsee it. The next time someone says a project “had potential,” you will think of the dashed circle at the top and the solid ball at the bottom, and you will ask the question the shirt does not ask: what was the ramp, and who decided where the ledge would be? That is a more useful question than the slogan, and it is the one the drawing earns.

The shirt does not answer it. It just puts the picture on a garment and lets you carry the question. That is a modest thing for a shirt to do, and it is more than most slogan shirts manage. The ball reached the bottom. The ramp is curved. The circle at the top is empty. The rest is yours to read.

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

The Periodic Table Tile That Isn’t Tungsten: Reading the ‘I Wear This Shirt Periodically’ Artwork

The shirt reads I WEAR THIS SHIRT PERIODICALLY in plain caps, and beneath that sit four tiles styled like periodic-table cells: 53 I, 74 W, 22 Ti, 16 S. The joke is supposed to be that the symbols spell the sentence. They don’t. Read the symbols in order and you get I W Ti S. The word periodically is not assembled from element symbols at all. It is just a word, sitting above a row of tiles that almost spell something else.

That gap is the interesting part. A periodic-table pun usually works by substitution: you swap letters for symbols, the reader decodes, the sentence resolves. Here the substitution is incomplete. The tiles give you four elements and a near-miss. The adverb does the semantic work; the tiles do the visual work; the two never quite meet. It is a diagram that has been asked to carry a sentence it cannot carry.

I keep thinking about this as a small specimen of a familiar workplace artifact: the terse message that looks like a specification but is actually a gesture. The tiles are formatted like data. Atomic numbers, symbols, the visual grammar of the table. They invite the reader to parse. And parsing produces I W Ti S, which is not a sentence, which is not even a word, which is the point if you find it funny and a defect if you don’t.

What the tiles actually say

Element 53 is iodine, symbol I. Element 74 is tungsten, symbol W. Element 22 is titanium, symbol Ti. Element 16 is sulfur, symbol S. The symbols are correct for those atomic numbers. The arrangement is correct for a left-to-right reading. What is missing is any element whose symbol would supply the e, r, o, d, i, c, a, l, l, y sounds that the sentence needs. The tiles are not a spelling. They are a rhyme.

This is not a chemistry claim, and I want to be careful about that. The shirt does not teach the periodic table. It does not demonstrate a reaction, a bond, or a property. It uses the table’s visual conventions as a typeface. The elements are chosen for their symbols, not their behavior. Tungsten is not especially periodic. Sulfur is not especially funny. The design is a typographic joke wearing a lab coat.

That distinction matters because the shirt is often described, in retail prose, as a chemistry pun. It is a chemistry-shaped pun. The shape is the periodic table; the pun is the word periodically, which means both “from time to time” and “in a periodic manner.” The tiles gesture at the second meaning. The sentence uses the first. The joke lives in the overlap, and the overlap is smaller than the design implies.

The difference between a slogan and a usable promise

Technical readers spend a lot of time around messages that look like specifications. A config key, an error string, a schema field name: each one is a compressed promise about what the system will do. retention.ms promises a duration. ON DELETE CASCADE promises a consequence. When those promises fail, we call it an incident.

A shirt slogan is not a specification. “I wear this shirt periodically” is a sentence about a habit, and the habit is deliberately vague. Periodically could mean weekly. It could mean once. It could mean the shirt is worn at intervals that the wearer declines to quantify. The tiles make it look precise — atomic numbers are precise — but the precision is decorative. The sentence remains a shrug in a lab coat.

I find that useful as a contrast, not as an analogy. The shirt is not a lesson about schema evolution. It is a reminder that visual grammar can imply rigor without supplying it. A row of numbered tiles looks like a data structure. It is not one. It is four elements and a missing word, arranged to be read quickly and understood loosely.

Why the near-miss is the design

If the tiles spelled the sentence exactly, the shirt would be a decoding exercise. You would read the symbols, get the word, and the joke would close. Instead the tiles stop short. I W Ti S is almost I wear this — the I and the W and the Ti and the S are doing phonetic work, not symbolic work — and then the sentence continues without them. The reader has to supply the rest. The design trusts you to hear it.

That is a specific kind of joke, and it has a specific failure mode. If you read the tiles as symbols, you get nonsense. If you read them as sounds, you get a fragment. The shirt only works if you do both at once and don’t mind the seam. It is a design that rewards a certain kind of reader — the one who has spent enough time around notation to know when notation is being used loosely — and mildly punishes the one who tries to parse it strictly.

I don’t think that is a flaw. I think it is the whole object. The shirt is not a puzzle with a solution. It is a joke about the expectation of a solution. The periodic table is one of the most orderly diagrams in common circulation. Putting a vague adverb next to it, and four tiles that almost spell the sentence, is a small act of visual misdirection. The order is the setup. The missing letters are the punchline.

What the shirt is, and what it isn’t

The object is a standard t-shirt from Quirky Cotton Collective, listed as I Wear This Shirt Periodically Funny Chemistry Science Pun. The design is the sentence plus the four tiles. That is the whole visual program. There is no second joke hidden in the atomic numbers, no alternate reading in the element names, no diagram of a reaction. The shirt is a sentence and a near-miss, printed on fabric.

It is not a chemistry lesson. It is not a statement about how often the wearer does laundry, or how often they go to the lab, or how often they think about the periodic table. The word periodically is doing double duty, and the tiles are doing visual duty, and neither is doing the other’s job. That is the design’s economy and its limit.

For a technical reader, the appeal is probably not the chemistry. It is the shape of the joke: a precise-looking notation that resolves into a vague claim. We spend our working lives trying to make messages mean exactly one thing. This shirt is a message that means two things at once and refuses to choose. Wearing it is not a technical statement. It is a small, legible preference for the kind of ambiguity that doesn’t page anyone at 3 a.m.

The maintenance burden of a near-miss

Every design that relies on a near-miss creates a small maintenance burden: the reader who tries to complete it. Someone will look at the tiles and try to spell periodically with element symbols. They will get stuck. They may ask. The answer is that the tiles don’t spell it, and the shirt doesn’t claim they do. The sentence is the sentence. The tiles are the decoration. The gap between them is the joke, and the joke requires a certain tolerance for unresolved notation.

That tolerance is not universal. Some readers will find the near-miss sloppy. Some will find it clever. The shirt does not arbitrate. It sits there, four tiles and a word, and lets the reader decide whether the seam is the point or the defect. I think it is the point. A periodic table that spelled the sentence would be a diagram. A periodic table that almost spells it is a joke about diagrams. The shirt is the second thing, and it is better for it.

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

Yesterday’s Update Arrived After Today’s Delete: Writing Replay-Safe Merges When CDC Event Time Isn’t Monotonic

A row gets deleted at 14:02. The delete event reaches your warehouse. The row is gone. At 14:07, a Kafka consumer lag spike flushes an update for the same primary key that was committed at 13:58. Your incremental model merges it in. The row is back.

This is not a freshness bug. It is a precedence bug. The merge had no way to know that the incoming update was older than the delete already applied, because the only ordering signal it carried was event_time, and event_time is exactly the column that is not monotonic in a CDC stream.

This article is about the mechanics of that failure and the cheapest structural fix: carry a monotonic ordering key alongside event time, and make the merge conditional on it. Everything below is grounded in what the source systems actually document about ordering, and priced in the hours and schema changes the fix costs.

The failure shape, precisely

Debezium’s PostgreSQL connector produces a change event for every row-level insert, update, and delete it captures, and streams them to a Kafka topic per table (Debezium PostgreSQL connector documentation). Each event carries the row’s data and metadata, including the source’s log position. The connector records the WAL position for each event and, on restart, continues reading from where it last left off.

That last sentence is the guarantee you actually have: the connector resumes from a recorded position. It is not a guarantee that the events arrive at your warehouse in commit order. Between the connector and your merge, there is a Kafka topic with partitions, a sink connector with its own retry and batching behavior, and often a staging table or a dbt model with a filter. Any of those can reorder, delay, or replay a record relative to its neighbors.

PostgreSQL’s own logical replication documentation is explicit that the subscriber applies changes in the same order as the publisher, so transactional consistency is guaranteed within a single subscription (PostgreSQL logical replication). That is a strong guarantee at the replication layer. It says nothing about what happens after the events leave that layer and land in a table that is merged by a scheduled job.

So the failure is not that the source lost ordering. The failure is that the ordering information was dropped somewhere between the source and the merge, and the merge fell back to a timestamp that does not encode it.

Why the standard incremental filter cannot see this

The documented dbt incremental pattern filters on a cutoff taken from the target table:

select * from orders
where updated_at > (select max(updated_at) from {{ this }})

That is the example from dbt’s own incremental models best-practices page. The page also documents the failure mode directly: late-arriving records can be filtered out by a max(updated_at) cutoff, and the recommended mitigation is a lookback window. It then states the limit of that mitigation plainly: with a 3-day lookback, a record that arrives 4 days late is still missed.

Read that carefully. The lookback window is a time filter. It widens the set of rows the model considers. It does not establish which of two rows for the same key is authoritative. If a delete for order_id = 42 was applied at commit position 5000, and an update for order_id = 42 with an earlier event timestamp arrives on a replay, a lookback window that includes both rows will happily merge the update over the delete. The row comes back. The window did its job; the merge did not.

This is the class of bug that a dbt maintainer discussion names directly: with CDC data arriving out of order, the latest batch by ETL time is not the most recent state in terms of event time (dbt discussion #10672). The discussion is about a proposed event_time and microbatch feature; it raises the problem, it does not claim a shipped fix for out-of-order CDC.

Two clocks, and only one of them orders writes

Separate the two timestamps that get conflated in every CDC-fed model:

  • Event time — when the change happened in the source business process. This is the column your analysts filter on, and it is the column that is non-monotonic in the stream.
  • Ordering position — when the change became durable and was read by the capture process. In PostgreSQL this is the WAL position (LSN). In Iceberg, the spec assigns a sequence number to every successful commit, and the relative age of data and delete files relies on that sequence number (Iceberg table spec).

The invariant you want is last writer by commit order wins. Event time answers “when did this happen.” Ordering position answers “which version is authoritative.” A merge keyed only on the business key, with no ordering comparison, cannot enforce the second invariant no matter how wide the lookback window is.

This is also why the fix is not “use a better timestamp.” There is no business timestamp that is guaranteed monotonic across a source system’s writes, a capture process’s restarts, and a replay. The ordering position is the only column that is monotonic by construction, because it is assigned by the system that serialized the writes.

The mechanics: an ordering column and a conditional merge

The structural fix has three parts. None of them is exotic; the cost is in the schema change and the backfill, not in the SQL.

1. Carry the ordering column into staging

Debezium’s PostgreSQL connector already emits the source log position in the event metadata. The first step is to project it into a column in the staging model, alongside the business columns and event_time. Call it commit_lsn or source_sequence; the name matters less than the fact that it is carried end to end and never dropped by a select * that gets rewritten.

If you are on Iceberg, the equivalent is the snapshot sequence number, which the spec assigns per commit. If you are on a warehouse that does not expose a source sequence, you need a monotonic surrogate assigned at ingest — a Kafka offset plus partition, or an ingest-time sequence from the sink. The point is that it must be assigned by the system that serialized the write, not by the row’s business content.

2. Keep the latest row per key by ordering column

Before the merge, deduplicate the incoming batch by business key, keeping the row with the highest ordering value. This handles the case where a single batch contains both an update and a delete for the same key. Without this step, the merge’s behavior depends on row order within the batch, which is not something you control.

3. Make the merge conditional on the ordering value

The merge predicate must include the ordering comparison, not just the key match. In pseudocode:

merge into target t
using incoming i
on t.order_id = i.order_id
when matched and i.commit_lsn > t.commit_lsn then update ...
when not matched then insert ...

The i.commit_lsn > t.commit_lsn clause is what makes the merge replay-safe. Replaying an old window re-applies rows whose ordering value is lower than what is already stored; those rows lose the comparison and are ignored. The merge becomes idempotent by construction, not by hoping the replay window is narrow enough.

Note what this requires: the target table must store commit_lsn as a column, not just use it in the predicate. The comparison is against the stored value, so the column has to persist.

Deletes need a tombstone, not a physical delete

Here is the part that trips most implementations. If a delete physically removes the row from the target, there is nothing left to compare against. The next late-arriving update for that key finds no matching row, takes the when not matched branch, and inserts. The row is resurrected, and the conditional merge never gets a chance to reject it.

The fix is to represent deletes as tombstone rows: a row with the key, the ordering value, and a deleted_at or is_deleted flag, rather than a physical removal. The merge then compares ordering values against the tombstone. A late update with a lower ordering value loses the comparison and is ignored. A later legitimate re-insert with a higher ordering value wins, which is correct.

This is the same mechanism Iceberg uses at the file level: version 2 adds delete files that encode rows deleted in existing data files, so row-level deletes can be applied without rewriting the data files (Iceberg table spec). The delete is a record with an ordering relationship to the data, not an absence of a record. Your merge needs the same property at the row level.

The cost of tombstones is real: the target table grows with deleted rows, and every downstream query needs to filter on the flag. That is a maintenance tax you are choosing to pay in exchange for replay safety. The alternative — physical deletes and a merge that cannot see them — is cheaper to write and more expensive to debug at 2 a.m.

Backfill and replay: the same rule must hold

When you re-run a window — an Airflow backfill, a dbt --full-refresh, a manual replay of a Kafka partition — the same ordering rule must apply. If the replay path uses a different merge (for example, a delete+insert strategy that does not compare ordering values), the replay will re-apply stale rows and undo the protection the conditional merge provides in steady state.

This is where the lookback-window pattern and the ordering rule interact. The lookback window determines which rows the model considers. The ordering rule determines which of those rows wins. You need both, and they are not substitutes. A wide lookback with no ordering rule re-applies stale rows. A narrow lookback with an ordering rule still misses rows that arrive outside the window, but the rows it does see are merged correctly.

dbt’s documentation is honest about the drift that lookback windows cannot prevent: incremental models inevitably drift from the source data over time, and the documented reset is a periodic full refresh (dbt incremental models). A full refresh that rebuilds from the source with the ordering column intact will produce a correct table. A full refresh that rebuilds from a staging layer that dropped the ordering column will reproduce the bug at full scale.

Pricing the fix

The fix is not free, and the costs are specific:

  • Schema change on every CDC-fed target table. One extra column (commit_lsn or equivalent) plus, if you adopt tombstones, a delete flag. This is a migration on each table, not a one-time change.
  • A one-time backfill to populate the ordering column. Existing rows have no ordering value. You either backfill from the source’s log history (if it is still available) or accept that historical rows are treated as lowest-precedence until they are touched again. The second option is cheaper and leaves a known gap.
  • A conditional merge predicate that must be kept in sync across every model that touches the table. This is the ongoing maintenance tax. Every new incremental model on a CDC-fed table needs the same predicate, and every model that is refactored needs it preserved. A model that drops the predicate silently reintroduces the bug.
  • Tombstone storage and downstream filter changes. If you adopt tombstones, every downstream query that reads the table needs to filter on the delete flag. That is a change to every consumer, not just the merge.

Against that, the cost of not fixing it is a class of bug that is hard to detect and harder to attribute. A resurrected row looks like a data quality issue in a downstream report, not like a merge precedence bug. The time to diagnosis is measured in hours per incident, and the incidents recur every time a consumer lags or a partition is replayed.

What to check before the next replay

Before you run a backfill or a full refresh on a CDC-fed table, answer these questions:

  1. Does the staging model carry the ordering column? If it was dropped by a select that lists columns explicitly, the merge cannot use it.
  2. Does the target table store the ordering column? If it is only in the predicate and not persisted, the comparison has nothing to compare against on the next run.
  3. Are deletes represented as tombstones or physical deletes? If physical, a late update will resurrect the row and the conditional merge will not catch it.
  4. Does the replay path use the same merge as steady state? A backfill that uses delete+insert or append bypasses the ordering rule entirely.
  5. Which tables are exposed? Any table fed by CDC where the merge key is the business key and the only ordering signal is event_time is a candidate for this failure. The list is usually longer than expected.

The detection method for resurrected rows is a comparison between the source’s current state and the target’s current state for a sample of keys, run after a replay. If a key exists in the target but not in the source, and the target row’s ordering value is lower than the source’s last delete position, you have found one. This is a diagnostic you can run on your own systems; it does not require a vendor feature.

The tradeoff, stated plainly

The conditional merge with an ordering column is more complex than the documented incremental pattern. It requires a schema change, a backfill, a predicate that must be maintained across models, and — if you adopt tombstones — changes to every downstream consumer. That is a real cost, paid in hours and in the ongoing attention of whoever owns the models.

The alternative is to accept that late-arriving updates can resurrect deleted rows, and to detect and correct them after the fact. That is cheaper to build and more expensive to operate, because the correction is manual and the detection is after the fact.

The choice depends on how often your CDC pipeline replays, how much consumer lag you tolerate, and whether a resurrected row in a downstream report is a nuisance or an incident. What is not a choice is whether the standard timestamp filter can prevent it. It cannot, because it filters on the one column that is not monotonic. The ordering column is the only signal that answers the question the merge is actually asking: which version is authoritative.

FAQ

Doesn’t PostgreSQL logical replication guarantee ordering?

It guarantees that the subscriber applies changes in the same order as the publisher, so transactional consistency is guaranteed within a single subscription (PostgreSQL documentation). That guarantee applies at the replication layer. It does not extend to what happens after the events are written to Kafka, consumed by a sink, staged, and merged by a scheduled job. The ordering information has to be carried through those layers, not assumed to survive them.

Can’t I just widen the lookback window?

A wider lookback window includes more rows in the merge. It does not change which row wins. If the merge has no ordering comparison, a stale update still overwrites a newer delete regardless of whether the window is 3 days or 30. The window controls coverage; the ordering rule controls precedence. dbt’s own documentation notes that a lookback window still misses records that arrive later than the window, so drift persists even with a wide window (dbt incremental models).

Does Iceberg solve this for me?

Iceberg’s spec assigns a sequence number to every successful commit and uses it to determine the relative age of data and delete files. That is the same ordering principle at the file level. It does not automatically make your row-level merge replay-safe if the merge is keyed on a business key and a non-monotonic timestamp. You still need to carry an ordering value into the merge predicate. Iceberg gives you the mechanism; it does not give you the guarantee for your specific merge.

What about dbt’s microbatch and event_time features?

The dbt discussion that proposes event_time and microbatch incremental models names the out-of-order CDC problem directly: the latest batch by ETL time is not the most recent state in terms of event time (dbt discussion #10672). The discussion is a proposal, not a shipped fix for this scenario. Treat it as evidence that the problem is recognized, not as a solution you can rely on today.

How do I know if my tables are affected?

Any table fed by CDC where the merge key is the business key and the only ordering signal is event_time is a candidate. The diagnostic is a comparison between the source’s current state and the target’s current state for a sample of keys after a replay. If a key exists in the target but not in the source, and the target row’s ordering value is lower than the source’s last delete position, the merge has resurrected a deleted row. Run this on your own systems; it does not require a vendor feature.

Snowflake MERGE Failed With ‘Duplicate row detected from DML evaluation’: The Source Query Returned Two Rows for One Key

Snowflake MERGE Failed With ‘Duplicate row detected from DML evaluation’: The Source Query Returned Two Rows for One Key

The MERGE ran for weeks. Then a CDC replay lands a second version of the same customer row, or a late-arriving dimension record slips past the dedup step, and the statement fails with a duplicate-row error from DML evaluation.

The message points at the write. The defect is upstream, in the grain of the source query. Snowflake is not complaining that the target has duplicate keys. It is refusing to guess which of two source rows should win.

What Snowflake is actually objecting to

The MERGE documentation is explicit about the condition. When a merge joins a row in the target table against multiple rows in the source, and that target row is selected for update, the result is nondeterministic: the system cannot determine which source value to use.

That is not a data-quality warning. It is a correctness boundary. Snowflake’s documented behavior is to raise an error when ERROR_ON_NONDETERMINISTIC_MERGE is TRUE, which is the default. The same section of the docs lists the second nondeterministic case: a target row selected to be both updated and deleted.

So the failure is a guard, not a bug. It fires precisely when the source side of the join is not one row per join key.

Reproduce the condition before you touch the pipeline

You do not need the failing MERGE to diagnose this. Count source rows per join key. If any key has a count above one, the MERGE is nondeterministic by construction.

-- Replace the join key and source expression with your own.
SELECT
    customer_id,
    COUNT(*) AS source_rows
FROM (
    -- paste the exact subquery from your MERGE ... USING ( ... )
    SELECT customer_id, updated_at, status
    FROM raw.customer_cdc
    WHERE ingested_at >= '2026-10-01'
) AS src
GROUP BY customer_id
HAVING COUNT(*) > 1
ORDER BY source_rows DESC;

Run this as a standalone statement, not inside the MERGE. The output is the list of keys that will trip the guard. If the result is empty, the duplicate is coming from somewhere else in the source expression — a join fan-out inside the subquery, for example — and you should count rows per key at each intermediate step until the count diverges.

This is the cheapest diagnostic in the article. It costs one query and tells you whether the problem is real before you spend an hour reading the MERGE text.

The two documented fixes

The MERGE documentation offers two paths to a deterministic statement.

Collapse the source to one row per key. The docs recommend GROUP BY in the source clause so that each target row joins against at most one source row. Their example uses MAX(v) grouped by the key, which makes the chosen value explicit rather than arbitrary.

Make exactly one source row satisfy the matched clause. A merge is deterministic if exactly one source row satisfies a WHEN MATCHED ... THEN UPDATE clause and no other source rows satisfy any WHEN MATCHED clauses. This is the same invariant stated from the other direction: one winner per target row.

Both fixes are the same fix. The source must be deduplicated before the MERGE evaluates it.

The deduplicating CTE pattern

A CTE is a named subquery defined in a WITH clause, usable as a temporary view within the statement that defines it. That makes it a natural place to enforce the one-row-per-key invariant without changing the MERGE’s matched and not-matched logic.

WITH deduped_source AS (
    SELECT
        customer_id,
        updated_at,
        status,
        ROW_NUMBER() OVER (
            PARTITION BY customer_id
            ORDER BY updated_at DESC, ingested_at DESC
        ) AS rn
    FROM raw.customer_cdc
    WHERE ingested_at >= '2026-10-01'
)
MERGE INTO analytics.dim_customer AS tgt
USING (
    SELECT customer_id, updated_at, status
    FROM deduped_source
    WHERE rn = 1
) AS src
ON tgt.customer_id = src.customer_id
WHEN MATCHED THEN UPDATE SET
    tgt.updated_at = src.updated_at,
    tgt.status = src.status
WHEN NOT MATCHED THEN INSERT (customer_id, updated_at, status)
    VALUES (src.customer_id, src.updated_at, src.status);

ROW_NUMBER() returns a unique row number for each row within a window partition, starting at 1 and continuing sequentially. Filtering to rn = 1 leaves exactly one row per customer_id, which is the invariant the MERGE needs.

The ORDER BY inside the window is where you encode your business rule. updated_at DESC picks the most recent version. ingested_at DESC breaks ties by arrival order. If neither column exists in your source, you have a different problem: the source has no defined recency, and no dedup pattern can invent one.

Snowflake’s QUALIFY clause can replace the nested subquery. It filters the results of window functions and is evaluated after window functions are computed, so the ranking and the filter can sit in one SELECT:

SELECT customer_id, updated_at, status
FROM raw.customer_cdc
WHERE ingested_at >= '2026-10-01'
QUALIFY ROW_NUMBER() OVER (
    PARTITION BY customer_id
    ORDER BY updated_at DESC, ingested_at DESC
) = 1;

Either form works. The CTE version is easier to test in isolation because you can run the SELECT without the MERGE and inspect the row count per key.

Why ROW_NUMBER beats GROUP BY with MAX in most CDC sources

The docs’ GROUP BY example is correct and sufficient when the source has one meaningful value column. It becomes awkward when the source has many columns that must stay consistent with each other.

MAX(v) GROUP BY k aggregates each column independently. If updated_at comes from one row and status comes from another, the merged row is a composite that never existed in the source. That is not a Snowflake defect; it is what independent aggregation does. ROW_NUMBER filtered to rank 1 keeps the full payload of a single source row, so the target receives a row that actually existed upstream.

This is a design preference, not a documented requirement. If your source has one value column and no recency ordering, GROUP BY is simpler and the docs already bless it.

The INSERT-side asymmetry that partial fixes miss

Here is the trap. The duplicate-row error fires on the matched branch. Teams fix that branch, ship, and later discover doubled rows in the target for brand-new keys.

The documentation explains why. If the MERGE contains a WHEN NOT MATCHED ... THEN INSERT clause, there are no matching rows in the target, and the source contains duplicate values, then the target gets one copy of the row for each copy in the source. No error. No warning. Just duplicates.

So a dedup applied only to the WHEN MATCHED path is not a fix. It silences the loud failure and leaves the silent one. The dedup must cover the entire source subquery, which is why the CTE pattern above wraps the whole USING clause rather than a single branch.

If you have already shipped a partial fix, check the insert side directly:

SELECT customer_id, COUNT(*) AS target_rows
FROM analytics.dim_customer
GROUP BY customer_id
HAVING COUNT(*) > 1;

Any row here is evidence that the source duplicates reached the target through the insert path.

The tempting one-line fix, and what it costs

You can set ERROR_ON_NONDETERMINISTIC_MERGE = FALSE. The docs say what happens next: one row from among the duplicates is selected to perform the update or delete, and the row selected is not defined.

That is the entire trade. The statement succeeds. The winning row is undefined. The same MERGE can produce different target values on different runs, and nothing in the query text tells you which run you got.

For a pipeline that feeds a dimension table, this converts a loud failure into silent dimension drift. The drift is not reproducible, so it cannot be debugged from the error log. It surfaces later as a report that disagrees with the source system, and the investigation starts from the report rather than from the MERGE.

The parameter is documented and legitimate for cases where any source row is acceptable. If your business rule is genuinely “any of these is fine,” setting it to FALSE is honest. If your business rule is “the latest one wins,” setting it to FALSE is a correctness debt that the next on-call engineer inherits without a ticket.

Price the fix in hours, not sprints

The deduplicating CTE is a few lines inside the source subquery. It does not change the target schema, the matched clauses, or the orchestration. It is reviewable in one sitting by someone who knows the source table’s grain.

The pre-flight count is one query. Run it as a separate statement in the pipeline, or as a dbt test on the source model, and the regression is caught before the MERGE executes rather than after it fails.

The alternative — flipping the session parameter — is a one-line change that costs nothing today and shifts the cost to whoever debugs the drift. That is the maintenance tax this architecture charges: the fix that makes the error go away is cheaper than the fix that makes the data correct, and the difference is paid later by someone who was not in the room.

What to assert before every MERGE

Treat “source rows per join key = 1” as an invariant, not an error to suppress. The diagnostic is the grouped count. The fix is the dedup in the source. The parameter is not a fix.

When the error fires again — and on a CDC-fed source it will — start at the source subquery’s row count per key. The message names DML evaluation, but the defect is in the grain of the query that feeds it.

FAQ

Does this error mean my target table has duplicate keys?

No. The documented condition is multiple source rows matching one target row under a matched update or delete. The target’s key uniqueness is a separate question, and the pre-flight count above checks the source, not the target.

Why did the MERGE work for weeks and then fail?

The source grain changed. A CDC replay, a backfill, or a late-arriving record added a second row for a key that previously had one. The MERGE text did not change; the data feeding it did.

Can I just add DISTINCT to the source?

DISTINCT collapses identical rows. If the two source rows differ in any selected column — a different updated_at, a different status — DISTINCT leaves both, and the MERGE still fails. You need a rule for which row wins, which is what ROW_NUMBER with an ORDER BY provides.

Is setting ERROR_ON_NONDETERMINISTIC_MERGE = FALSE ever correct?

Only when any matching source row is genuinely acceptable for the update. The docs state the selected row is not defined, so if your downstream consumers depend on which value lands, the parameter is not a fix.

Does the dedup need to cover the INSERT branch too?

Yes. Source duplicates with no target match are inserted once per source copy rather than raising an error. A dedup applied only to the matched branch leaves the insert path open to silent duplicates.

Where can I read the exact rules?

The Snowflake MERGE documentation covers the nondeterministic cases, the ERROR_ON_NONDETERMINISTIC_MERGE behavior, the GROUP BY remedy, the deterministic-merge conditions, and the insert-side duplicate behavior. The ROW_NUMBER and QUALIFY pages cover the ranking and filtering mechanics used above.

The Composition Notebook That Isn’t One: Reading the Ghost-and-Pumpkin Cover as a Costume

The shirt shows a rectangle of black-and-white speckle, a dark binding strip down the left edge, and a white ruled label headed COMPOSITION. Inside the label, an outlined ghost and an outlined pumpkin sit on the ruled lines. That is the whole design. It is a printed notebook cover, not a physical notebook, and the retail title calls it a costume.

That distinction is the useful part. A costume is a representation of an object, worn on a body, that asks the viewer to complete the reference. The shirt does not hand you a notebook. It hands you the look of one and trusts you to recognize the genre: the speckled board, the taped spine, the label with the wide rule and the name line. The ghost and pumpkin are not decoration added to a school supply. They are the joke that turns the supply into a Halloween costume.

Read the label closely. The word COMPOSITION is set in the header position, above the ruled field, exactly where a student would write a name or a subject. The ghost and pumpkin occupy that field instead. The design does not print a name. It prints the outline of two figures where a name would go. That is a small, specific visual argument: the notebook is not being used for writing. It is being used as a mask.

Why the speckle matters more than the ghost

The ghost and pumpkin are the readable gag. The speckle is the load-bearing part. A plain black rectangle with a white label would read as a generic folder or a shipping label. The black-and-white fleck is what makes the rectangle read as a composition book — the marbled cover board that generations of students have carried. Remove the speckle and the costume collapses into a blank tag. Keep the speckle and the viewer supplies the rest: the wide-ruled pages, the cardboard cover, the cheap binding that fails in November.

That is a useful thing to notice about visual shorthand in general. The most recognizable part of an object is often not its function but its surface. The composition book is a writing tool, but its identity lives in the cover pattern. The shirt borrows that pattern and skips the tool. What remains is a surface that says school without saying write.

The costume logic of a group shirt

The retail title includes Teacher Group Halloween. That phrase is doing real work. A single person wearing a printed notebook cover is a mild visual pun. A group of people wearing the same printed notebook cover is a costume: the matching set is the joke. The design is built for repetition, not for individual detail. There is no name field filled in, no subject written, no personal variation. Every shirt in the group shows the same blank label with the same ghost and pumpkin. The uniformity is the point.

This is where the shirt differs from a slogan tee. A slogan asks you to read a sentence and agree or laugh. This design asks you to recognize a shape and place yourself inside a category — the teacher, the student, the staff member who is dressed as the thing they hand out. The ghost and pumpkin are the only concession to Halloween. The rest is institutional furniture.

I think that is why the design works better as a group object than as a standalone one. The composition book is a shared reference, not a personal one. Nobody has a favorite composition book. Everybody has used one. The shirt trades on that shared memory without making a claim about any individual wearer.

What the design does not say

It does not say teacher anywhere on the artwork. The word COMPOSITION is the only text on the label, and the ghost and pumpkin are the only figures. The teacher framing comes from the retail title, not from the printed design. That matters if you are trying to read the shirt as a statement about work. It is not a statement about work. It is a picture of a notebook cover with two Halloween shapes on it, and the rest is context supplied by the listing and by whoever wears it.

It also does not claim to be a real notebook. The retail observation is explicit: the teacher Halloween costume is a printed notebook cover, not a physical notebook. The shirt is a representation of an object, not the object itself. That sounds obvious, but it is the kind of distinction that gets lost when a design is described as a composition notebook shirt. The keyword describes the reference, not the material. You are not wearing a notebook. You are wearing a picture of one.

If you want the object itself, the Composition Notebook Costume Teacher Group Halloween shirt is the printed version. The design is a black-and-white speckled cover with a dark binding strip and a white ruled label headed COMPOSITION, containing an outlined ghost and pumpkin. That is what the artwork shows. Everything else — the group costume, the teacher context, the Halloween occasion — is framing around that image.

The maintenance burden of a borrowed surface

Every design that borrows a familiar surface inherits the maintenance work of that surface. The composition book cover is recognizable because it is standardized: the speckle, the label, the binding strip. A printed version has to keep those cues intact or the reference fails. The ghost and pumpkin are the variable part. The cover is the fixed part. If the cover stops reading as a composition book, the costume stops working, and no amount of Halloween decoration fixes it.

That is the tradeoff this shirt makes. It spends its visual budget on fidelity to a cheap school supply and saves its joke for two small outlines inside the label. The result is a design that is legible at a distance and slightly disappointing up close, which is roughly the same experience as looking at an actual composition book. I mean that as a compliment. The shirt is not trying to be more than the thing it depicts.

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