PAPER-2025-012

The Cumulative State Anti-Pattern

When "Current" Masquerades as "Ever"—how ambiguous field semantics create invisible bugs that punish users for legitimate actions.

Methodology 8 min read Intermediate

Abstract

A template creator delisted several of their published templates to maintain quality standards. The system responded by revoking their "established creator" privileges—blocking new submissions. The bug wasn't in the logic; it was in the semantics. A field named "Templates Published" tracked current state, not cumulative achievement. This paper examines how ambiguous field naming creates invisible bugs, proposes a naming convention that prevents them, and reflects on the Heideggerian notion that tools should recede into use—not punish users for using them correctly.

Bug published >= 5 Penalizes curation
Fix published + delisted >= 5 Preserves achievement

Name your fields for what they truly represent— their semantics, their behavior— not for what they merely store: their content.

Click to reveal

6
Templates Delisted
Lost
Creator Status
1
Line Changed
Restored
After Fix

I. The Incident

Izhaan, a prolific Webflow template creator, noticed something wrong. After delisting several templates that no longer matched their quality standards, they could no longer submit new templates. The system reported they had "an active review in progress"—but they didn't.

// The error message:

"You already have an active review in progress.

Please wait for the review to complete before

submitting another template."

The creator had done nothing wrong. They had curated their portfolio—a responsible action that benefits the marketplace. Yet the system punished them for it.

II. The Investigation

The validation system determined "established creator" status using a simple check:

if (publishedTemplates >= 5) {
  // Established creator: unlimited concurrent submissions
} else {
  // New creator: limited to 1 active review
}

The field publishedTemplates came from Airtable: #️⃣👛Templates Published. The assumption was clear: this counts how many templates a creator has ever published. With 10+ published templates, Izhaan should qualify as established.

But querying the API revealed the truth:

{
  "publishedTemplates": 4,
  "submittedTemplates": 11,
  "rejectedTemplates": 1,
  "delistedTemplates": 6
}

4 + 6 = 10. Izhaan had published 10 templates. But after delisting 6, the publishedTemplates field showed only 4—the currently published count.

The Semantic Trap

"Templates Published" sounds cumulative. It reads as achievement, history, record. But it tracked current state—a live count that decrements when templates are removed. The name lied.

III. The Arithmetic of Ambiguity

The system calculated "active reviews" using this formula:

activeReviews = submitted - published - rejected - delisted

With the correct semantics:

FieldValueMeaning
submitted11Cumulative: ever submitted
published4Current: now published
rejected1Cumulative: ever rejected
delisted6Cumulative: ever delisted
activeReviews011 - 4 - 1 - 6 = 0 ✓

The formula was correct. But the "established creator" check wasn't accounting for the semantic mismatch:

// Bug: uses current count, not cumulative achievement

publishedTemplates >= 5  // 4 >= 5 = false ✗

// Fix: include delisted to recover true achievement

publishedTemplates + delistedTemplates >= 5  // 4 + 6 = 10 >= 5 = true ✓

IV. The Anti-Pattern Defined

The Cumulative State Anti-Pattern occurs when:

  1. A field name implies cumulative history ("Templates Published")
  2. The field actually tracks current state (live count)
  3. Business logic assumes cumulative semantics
  4. State transitions (like delisting) break the assumption

The pattern is insidious because it works correctly until it doesn't. For creators who never delist, the bug never manifests. The field appears to work. Only when a user exercises a legitimate action does the semantic mismatch surface.

Related Anti-Patterns

Soft Delete Confusion

"Users" table includes soft-deleted records. Count queries return wrong totals depending on whether filters are applied.

Status vs. History

"OrderStatus" stores current state but business needs order history. Overwrites destroy audit trail.

Counter Cache Drift

Denormalized count field drifts from reality due to edge cases in increment/decrement logic.

Implicit Semantics

Field meaning lives in tribal knowledge, not schema. New developers make incorrect assumptions.

V. The Fix

The immediate fix was surgical—one line:

// Before: current state only

} else if (publishedTemplates >= 5 || isWhitelisted) {

// After: cumulative achievement

} else if (publishedTemplates + delistedTemplates >= 5 || isWhitelisted) {

But this is a patch, not a cure. The underlying issue—ambiguous field semantics—remains in the database schema. A proper fix would involve:

Current NameSemanticProposed Name
Templates PublishedCurrentTemplates Currently Published
Templates SubmittedCumulativeTemplates Ever Submitted
Templates RejectedCumulativeTemplates Ever Rejected
Templates DelistedCumulativeTemplates Ever Delisted

Or, introduce a new field: Templates Ever Published (cumulative) distinct from Templates Currently Published (current state).

VI. Tools That Punish

Heidegger distinguishes between tools that are ready-to-hand (zuhanden)—receding into transparent use—and tools that become present-at-hand (vorhanden)—forcing themselves into conscious attention through breakdown.

"The peculiarity of what is proximally ready-to-hand is that, in its readiness-to-hand, it must, as it were, withdraw in order to be ready-to-hand quite authentically."
— Heidegger, Being and Time

Izhaan's experience was worse than breakdown—it was betrayal. The system didn't just fail; it punished a correct action. Delisting low-quality templates is responsible curation. The tool should have supported this. Instead, it revoked privileges earned through legitimate achievement.

The Canon Principle

"The infrastructure disappears; only the work remains." When infrastructure punishes users for using it correctly, it has violated its fundamental purpose. Tools exist to enable, not to entrap.

The fix restores the tool to its proper mode: invisible, supportive, enabling. Established creators remain established regardless of how they curate their portfolios. The system recedes; the creative work continues.

VII. Prevention: Naming Conventions

The anti-pattern can be prevented through explicit naming conventions:

SemanticPrefix/SuffixExample
Current state"Current", "Active", "Now"current_published_count
Cumulative total"Total", "Ever", "Lifetime"total_published_count
Point-in-time"At", "As of", timestamppublished_at_signup
Derived/calculated"Computed", "Derived"computed_active_reviews

Schema Documentation

Beyond naming, document the semantics explicitly:

/**
 * templates_published: INTEGER
 *
 * Semantic: CURRENT STATE (not cumulative)
 * Behavior: Increments on publish, DECREMENTS on delist
 * Use for: Display of currently visible templates
 * NOT for: Achievement checks, historical queries
 *
 * Related: templates_ever_published (cumulative)
 */

VIII. Conclusion

The Cumulative State Anti-Pattern is a naming problem that manifests as a logic bug. When field names imply cumulative semantics but track current state, business logic built on those fields will eventually betray users who exercise legitimate state transitions.

The fix for Izhaan was simple: include delisted templates in the achievement calculation. The lesson is broader: name fields for their semantics, not their content. "Templates Published" tells you what's stored. "Templates Currently Published" tells you how it behaves.

"The difference between the right word and the almost right word is the difference between lightning and a lightning bug."

— Mark Twain

In database design, the difference between "published" and "currently published" is the difference between a system that supports its users and one that punishes them for success.

Appendix: The Complete Fix

// packages/io/workers/webflow-validation/src/routes/template.ts

// Extract user stats
const publishedTemplates = user.fields['#️⃣👛Templates Published'] ?? 0;
const rejectedTemplates = user.fields['#️⃣👛Templates Rejected'] ?? 0;
const submittedTemplates = user.fields['#️⃣👛Templates Submitted'] ?? 0;
const delistedTemplates = user.fields['#️⃣👛Templates Delisted'] ?? 0;

// Established creator check: include delisted to preserve earned status
if (publishedTemplates + delistedTemplates >= 5 || isWhitelisted) {
  // Unlimited concurrent submissions
  message = "You can have unlimited concurrent submissions for review.";
  hasError = false;
} else {
  // New creator: check active reviews
  // Formula accounts for all terminal states
  const activeReviews = submittedTemplates - publishedTemplates
                       - rejectedTemplates - delistedTemplates;

  if (activeReviews >= 1) {
    message = "You already have an active review in progress.";
    hasError = true;
  } else {
    message = "You can have 1 template submitted for review at a time.";
    hasError = false;
  }
}

References

  1. Heidegger, M. (1927). Being and Time. Trans. Macquarrie & Robinson.
  2. Fowler, M. (2002). Patterns of Enterprise Application Architecture. Addison-Wesley.
  3. Kleppmann, M. (2017). Designing Data-Intensive Applications. O'Reilly Media.
  4. CREATE SOMETHING. (2025). "CLAUDE.md: The Subtractive Triad."