Skip to content

Build1 publisher3 min readPublished

A margin rule overrides the $329 price floor once unit cost clears $293.75

A dev.to walkthrough builds a console pricer from six plain rules, a two-hour cooldown and a 30-minute freshness window, and the floor it clamps to is computed from unit cost, so the published $329 rarely binds.

The Engineer · Build desk

What happened

  • A dev.to walkthrough starts from the naive rule myPrice = competitorPrice - 1 and names its failure modes: a rival's loss-leading flash sale, a parser reading the wrong variant, and stock nearly gone.
  • Its console example sets six rules: up 12% above 50 units in 24 hours, down 7% below 15, a $329 floor, a $479 ceiling, competitor prices ignored past 30 minutes, and one change every two hours.
  • In the TypeScript version the effective floor is the larger of $329 and unit cost times 1.12, so the floor is computed from cost at every evaluation.
  • The code adds stock thresholds the rule list omits: an increase requires more than 20 units in stock and a decrease requires more than 50.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

  • constraint A crawler polling less often than every 30 minutes leaves the competitor branch unreachable at most evaluation times, so the scrape schedule decides whether rivals influence price at all.
  • decision Whoever moves unit cost moves the floor. Past $293.75 the $329 constant is inert, so a supplier increase quietly raises the minimum sale price without anyone editing the pricing config.
  • capability A blocked run is still written out as a decision naming the guardrail that stopped it. That makes the question of why a price did not move answerable from a table.
  • cost The two-hour cooldown buys stability at a fixed price: twelve moves a day per SKU, and a rival's flash sale can go unmatched for almost two hours by design.

Read `decidePrice` in the order it executes. The first thing it does is look at `lastPriceChangeAt`, and if the last change was less than 120 minutes ago it returns the current price with reason `no_change` and `blocked: "price_changed_too_recently"` [7]. Nothing downstream runs.

Then the floor is computed. `marginFloor` is `unitCost * (1 + MIN_MARGIN)` with `MIN_MARGIN` at 0.12, and `effectiveFloor` is the larger of that and the 329 constant [8][6]. So $329 binds only while unit cost sits at or below $293.75, which is 329 divided by 1.12 [17]. Above that cost the minimum tracks procurement, and `marginFloor` is the number that sets it. The file also uses 1.12 as a price multiplier in the demand branch [9]; that multiplier and the 0.12 margin are unrelated quantities that happen to share a digit [21].

The rule list and the code disagree about stock. The list says increase 12% above 50 units sold in 24 hours and cut 7% below 15 [4]. The code gates the increase on `stock > 20` and the cut on `stock > 50` [9]. With 20 units left and 60 sold, the price holds [20], and the post's own opening argument is that nearly empty inventory is when you should be raising price instead of chasing a competitor down [2].

The competitor adjustment runs after the demand branch and can only push the candidate lower. It needs an observation within 30 minutes and a competitor price below the candidate, then sets the candidate to `competitorPrice - 1` with reason `fresh_competitor_undercut` [10]. The last transformation is `clamp(candidate, effectiveFloor, PRICE_CEILING)` [11]. Because the clamp runs last, no rule can breach the floor.

Two constants set the system's clock. The 120-minute interval caps a SKU at 12 changes a day [18]. The 30-minute window means competitor data is usable only when a scrape landed in the previous half hour. The crawler needs 48 runs a day, 30 minutes into 24 hours, before that branch can fire at an arbitrary evaluation time [19]. Of those two rules the post says: "Without them, prices can oscillate all day or react to bad data." [5]

The audit trail is two tables. `price_observations` carries source, price, `observed_at` and a metadata jsonb; `pricing_decisions` carries old price, new price, reason and the inputs jsonb [12]. The post's stated reason for the split is that "Amazon is cheaper" and "our scraper last saw Amazon cheaper 4 hours ago" are different facts [13]. Blocked requests that are not modelled as failures look like missing products [14], and the post recommends a tool called Wire for collecting competitor prices as inspectable observations [15].

The constants belong to one console. For 12% up at 50 units and 7% down at 15 to transfer, your demand would have to respond on a two-hour granularity at a comparable elasticity. Your own static floor would have to sit above cost plus margin to matter at all [4][17]. The ordering is what carries over: inputs, then rules, then guardrails, then the record of why [3].

What to watch

  • Whether a follow-up reports what the guardrails actually blocked in production: counts of price_changed_too_recently against floor clamps would show which constant fires most.
  • Any measured elasticity behind the 12% and 7% steps, which the post presents as example values for one console.
  • Whether the rule list is reconciled with the stock gates in the code, since the two disagree on what happens when inventory runs low.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories