Re-render only the SKUs that changed: hash rows for a Sume bulk run

Retail surveys cite inventory imbalance and reactive decisions. Hash each product row, then send only changed rows to a Sume bulk queue with a revision key.

6 min readSume
All posts

How do you refresh holiday videos when stock or offers change without re-rendering everything? Hash each product row and send only the rows whose hash changed. A KTVZ report (published 2026-09-30, read 2026-10-04) cites a Kase survey of 328 retail leaders in which 52% name inventory imbalance, 79% expect to make reactive decisions and 85% are increasing inventory. Whatever your store's numbers are, the pattern is the same: rows change late and often.

On the Sume side, the tools are a bulk queue of up to 100 items and an Idempotency-Key that you derive from the row's content, so an unchanged row is never submitted twice by accident.

The idea

Keep a small table of SKU, row hash and the last run id. When the nightly feed arrives, compute the hash of each row's fields that affect the video: name, offer text, price, image URL. Rows with the same hash as last time are skipped. Changed and new rows go into one queue, chunked at 100, with concurrency as your window.

Put the hash, or a short prefix of it, into the key. Keys are scoped to one Format, can be up to 255 characters, and a spent key replays 202 with the old queue, so the same changed set submitted twice yields one queue.

Code: find the changed rows

This script hashes rows, compares with the stored hashes and builds the queue body plus a key for the batch.

import hashlib
import json


def h(row):
    return hashlib.sha256(json.dumps(row, sort_keys=True).encode()).hexdigest()


stored = {"mug-01": h({"sku": "mug-01", "offer": "20%"})}
feed = [
    {"sku": "mug-01", "offer": "20%"},
    {"sku": "mug-02", "offer": "15%"},
]
changed = [r for r in feed if stored.get(r["sku"]) != h(r)]
batch_hash = h([h(r) for r in changed])[:12]
body = {"concurrency": 4, "items": [{"input": r} for r in changed]}
print("key:", f"feed-{batch_hash}")
print("changed:", [r["sku"] for r in changed])
assert [r["sku"] for r in changed] == ["mug-02"]

Edge cases

Hash only the fields that change the video. If a stock count alone changes and the video shows no stock figure, a hash of the whole row triggers a render you did not need. Keep a list of fields per Format.

Version the hash. When you edit the Format's files, every old hash is stale for that Format. Include a Format version, or a counter you bump, in the hash, so a recipe change triggers a refresh by design.

Finally, cap the blast radius. Set generation_spend_cap_usd per item and cap the number of rows per night, so a bad feed that changes every row does not queue the whole catalog.

Handle the results

When a child finishes, write its run id and the new hash together, so a half-finished queue never marks a row as current. If a child fails, leave the old hash in place and the row will be picked up in the next feed. Branch on the queue's counts.failed, since completed only means every item is terminal.

If one scene of a video must change but the rest is fine, continue the previous run with previous_run_id instead of starting over.

What each field is for

Fields in the refresh loop, Sume docs and KTVZ article read 2026-10-04
FieldWhere it livesPurpose
Row hashYour tableDetect a change
Idempotency-KeyHeader or body, per FormatMake a resend safe
items[i].inputQueue bodyCarry the row to the Format
counts.failedQueue receiptKnow what to retry

Sources

Related posts

More in Use cases

All Use cases posts

Written by Sume