to select ↑↓ to navigate
Navgold

Navgold

Open in ChatGPT
Ask ChatGPT about this page
Open in Claude
Ask Claude about this page

Pricing Guardrails and Safety Controls

Navgold applies layered safety controls before any price or stock reaches Amazon or Repricer.com. Every control is configured on the Navgold Settings singleton and enforced in code — most of them at the outbound chokepoint, so a block happens before any HTTP call leaves the system.

The outbound chokepoint

flowchart LR
  A[Refresh strategies<br/>compute min/max] --> B[Build feed<br/>build_pricing_feed]
  B --> C{Guards}
  C -->|freeze on| X1[BLOCK<br/>AmazonFrozenError]
  C -->|Dry Run| X2[BLOCK<br/>PricingNotApprovedError]
  C -->|deviation too far| X3[SKU dropped from feed]
  C -->|price <= cost / min>max| X4[SKU flagged, not published]
  C -->|all pass| D[Feeds.create_feed_document<br/>Feeds.create_feed]
  D --> E[Amazon SP-API]

Feeds.create_feed_document, Feeds.create_feed and RepricerClient.post_repricer_data each call the freeze + approval guards before the transport call, so a frozen or un-approved system never emits a request.

Controls at a glance

Control Navgold Setting(s) Default What it does
Freeze / kill-switch freeze_amazon_outbound Off Hard-blocks all outbound (feeds + repricer) at the chokepoint
Loss circuit-breaker enable_loss_circuit_breaker, loss_circuit_breaker_threshold (GBP) Off / — Auto-sets the freeze when below-min losses in a rolling window exceed the limit
Dry-Run / Live approval gate pricing_sync_mode (Dry Run / Live), enable_pricing_sync Dry Run / Off Dry Run renders a preview and never pushes; going Live requires explicit approval
Price-deviation band price_change_threshold_percent, price_change_block_direction 20% / Both Drops a SKU from the feed if its new price moves too far from the current live price
Below-cost floor & band (per-strategy min/max) Never publishes a price at/below purchase cost, ≤ 0, or with min > max
Oversell / stock reserve stock_reserve_pct, stock_publishing_mode 0% / Publish Actual Stock Holds back a % of stock, caps quantity, and can force zero-stock publishing
Refresh-stagger guard (internal, pause_strategy_refresh) Off Never submits a feed built from half-refreshed prices

Freeze / kill-switch — freeze_amazon_outbound

The master stop. When on, block_if_amazon_frozen() raises AmazonFrozenError inside Feeds.create_feed_document, Feeds.create_feed, and the Repricer client — before any request is built. A blocked submission is logged as Skipped (not a failed sync), so it never pollutes the failed-sync triage queue.

Loss circuit-breaker — auto-freeze on real losses

An automatic version of the kill-switch. On every Sales Order below its minimum price, check_sales_order_below_min records the loss into a rolling time-window (Redis) and calls trip_circuit_breaker_if_needed(window_loss):

  1. If enable_loss_circuit_breaker is off → do nothing.
  2. If loss_circuit_breaker_threshold ≤ 0 or the window loss is below the threshold → do nothing.
  3. If already frozen → do nothing (idempotent).
  4. Otherwise → set freeze_amazon_outbound = 1 and alert.

A scheduled sweep_circuit_breaker() re-checks recent below-min sales independently, so a burst that slipped past the per-order path still trips the freeze. Thresholds are in GBP.

Dry-Run / Live approval gate — pricing_sync_mode

Outbound pricing runs in Dry Run by default:

  • Dry Run — the scheduled sync renders the exact feed a live push would send and stores it as a preview + variance report, then stops. block_if_pricing_not_approved() raises PricingNotApprovedError at the chokepoint. Nothing reaches Amazon.
  • Live — requires explicit approval (approve_and_go_live, System Manager only), which stamps pricing_sync_approved_by/_at. revert_to_dry_run flips it back and re-blocks all outbound.

enable_pricing_sync is the master switch above this — with it off, no scheduled submit runs at all.

Price-deviation band — price_change_threshold_percent + price_change_block_direction

Guards against a spiked/crashed price shipping. A SKU whose new price deviates from its current live selling price by more than price_change_threshold_percent (default 20%) is dropped from the feed and recorded in blocked_price_deviation. The direction filter narrows it:

  • Both — block large moves either way (default)
  • Drops Only — block large drops, allow rises
  • Increases Only — block large rises, allow drops

A SKU with no current selling price is blocked (fail-closed).

Below-cost floor & band integrity

Independent of deviation, the feed validators refuse to publish a price that is:

  • at or below the purchase cost (below-cost leak),
  • ≤ 0, or
  • an inverted band (min > max, or min == max without a fixed price).

Flagged SKUs are excluded from the price feed rather than shipped.

Oversell / stock reserve — stock_reserve_pct + stock_publishing_mode

Stock safety before the quantity is published:

  • stock_reserve_pct — holds back a percentage of available stock (a negative reserve is clamped to 0; ≥ 100% publishes nothing).
  • Bundles — quantity is capped to the buildable qty from components; an unbuildable bundle publishes 0.
  • FBA — FBA-fulfilled SKUs publish quantity 0 on the merchant channel (Amazon owns the stock).
  • stock_publishing_modePublish Actual Stock (default), or force Publish Zero Stock for all / selected items.
  • AFN safety — a failed Amazon inventory pull never zeroes existing stock (it aborts and alerts), so an API blip can't cause an oversell.

Refresh-stagger guard

Strategy refresh runs at :00/:30 and submits at :15/:45. If a refresh over-ran or never ran, the submit defers rather than shipping a feed built from half-refreshed prices. pause_strategy_refresh stops the scheduled refresh entirely.


Every control on this page is verified by automated tests that assert the unsafe path is blocked — see the Test Coverage & CI page under Engineering — not just the happy path.

Last updated 1 month ago
Was this helpful?
Thanks!