Proof, not promises

Engineering receipts for the claims that matter.

Powerful, flexible and fast are cheap words. This is where PerkRule explains the architecture, constraints and tradeoffs behind the product.

RECEIPT 01 / NATIVE OWNERSHIP

Why PerkRule does not replace WooCommerce coupons.

WooCommerce already has a coupon domain model, data stores and ecosystem expectations. PerkRule keeps WC_Coupon canonical and adds only the promotion concepts WooCommerce does not natively own.

AUTHORITY BOUNDARY

WooCommerce remains canonical for coupons, carts, orders and native discount arithmetic.

PerkRule does not introduce a coupon table or duplicate the fields WooCommerce already owns. Native description, publish/draft status, expiration, restrictions and monetary calculation remain WooCommerce state. PerkRule metadata exists only for additional promotion concepts. This keeps normal WooCommerce CRUD and ecosystem expectations intact and means disabling PerkRule does not require reconstructing a second proprietary coupon model before the store can understand its coupons again.

PERSISTENCE DISCIPLINE

Native values change through WC_Coupon CRUD, and PerkRule configuration stays explicitly namespaced.

The repository normalizes codes through WooCommerce, uses WC_Coupon setters and save operations, and treats collisions or failed restoration as real persistence failures rather than ambiguous false/null states. Complex PerkRule definitions use transparent versioned JSON rather than PHP serialization. The point is not merely stylistic purity: a clear persistence boundary makes rollback, migrations, HPOS compatibility and third-party interoperability easier to inspect and test.

RECEIPT 02 / CHECKOUT SAFETY

What is forbidden from live cart evaluation.

Licensing calls, updates, telemetry, migrations, DDL, CSV work and full coupon scans do not belong in the checkout hot path. Promotion decisions must remain local and bounded.

HOT-PATH LAW

Checkout is not the place to discover schemas, phone home or perform administrative work.

Live cart evaluation excludes remote licensing, update checks, telemetry transmission, migrations, DDL, CSV processing, all-coupon scans and purchase-history queries. Schema-dependent services start only when a bounded schema-version snapshot exactly matches the code expectation. If the schema is stale, those services stay out of the request while WooCommerce keeps operating. The failure mode is reduced PerkRule capability, not a checkout attempting database repair in front of a customer.

BOUNDED WORK

Correctness is paired with explicit limits so a promotion rule cannot quietly turn into unbounded checkout work.

Rule documents have limits on encoded size, depth and node count. Candidate discovery has a hard capacity. Cache keys and identifiers are bounded. Conflict resolution is deterministic rather than combinatorial, and Best Deal scoring is restricted to contested candidates inside explicit groups. These limits are part of the architecture because 'works on my test store' is not enough when the same code may run repeatedly during cart and checkout recalculation.

RECEIPT 03 / AUTO APPLY

Automatic does not mean uncontrolled.

Auto Apply uses the same validation path as manual coupons, mutates through WooCommerce public APIs and tracks ownership so PerkRule does not remove a coupon the customer applied themselves.

VALIDATE BEFORE MUTATING

Auto Apply reuses the same eligibility logic instead of inventing a second, more permissive path.

Each automatic candidate passes through PerkRule's coupon validation service, which preserves native WooCommerce validity and evaluates the subject coupon against an immutable context where that same coupon is excluded from the applied-coupon snapshot. That avoids a coupon accidentally satisfying a rule that depends on itself. Only candidates that survive native validity, PerkRule rules and policy resolution can reach the mutation stage.

OWNERSHIP PROVENANCE

The runtime tracks successful automatic mutations, not merely coupons configured as automatic.

This distinction protects customer intent. PerkRule can remove an obsolete coupon only when it has explicit session provenance showing that PerkRule applied it. Removing it clears that ownership marker, so a later manual application cannot inherit stale ownership. Manual and unrelated coupons remain protected constraints during reconciliation, including when individual-use or exclusivity rules make an automatic candidate incompatible with the current cart.

RECEIPT 04 / STACKING

Why conflicts resolve before mutation.

Priority, exclusivity, conflict groups and Best Deal are planned first. A deterministic plan reduces order-dependent behavior and makes failure modes easier to reason about.

DETERMINISTIC ORDER

The same eligible state should produce the same selection plan regardless of incidental traversal order.

Phase 09 resolves candidates using explicit policy: Best Deal score where applicable, then priority, then a stable coupon-ID tie-breaker. Stack, exclusive, conflict-group and Best Deal modes describe relationships between promotions without weakening WooCommerce's native individual-use rules. A protected manual coupon is never evicted merely so an automatic promotion can make its own policy easier to satisfy.

ISOLATED SCORING

Best Deal trials happen on cloned cart state rather than by experimenting on the shopper's live cart.

Only contested Best Deal candidates are scored. The scorer clones the cart and line product objects, adds a common protected-coupon baseline plus one candidate, and lets native WooCommerce totals behavior calculate the candidate's monetary effect. It does not call the public live-cart calculate_totals flow for a trial, write session state or emit notices. If a score fails, reconciliation aborts before the real cart is mutated.

Start with the product the notes describe.

Product 001 brings these constraints together into one WooCommerce promotions engine.

Explore Product 001

PerkRule support room

Real support works better when people can talk.

The PerkRule Discord will be the direct place for setup questions, bug reports, compatibility notes and release discussion. Useful answers should not disappear into private tickets — recurring problems can become documentation and Engineering Notes.

Discord opens around Product 001 release