Wiki · Workflow companion

Item record review + push-back

The items catalog cleanup workhorse. Query an item record across every surface (NS fields, spec sheet, pricing, vendor costs, assembly memberships, recent transactions), propose targeted field updates, and after Mike's tap push back to NS and invalidate every dependent cache.

Mixed · Some steps live, others stubbed
What this is

Item record review + push-back

Item record review is the items-side counterpart to assembly_build_review. It's the workhorse Mike uses on the data-cleanup loop — open an item, see its full live state, propose specific field updates, and push the cascade.

The cascade is deliberately wide because items touch a lot: NS fields, spec sheets, pricing_master rows, vendor_costs, assembly memberships, open bid lines, recent transactions. Changes ripple to all of them; the workflow makes the ripple deterministic.

Risk level 3 (medium). Contract at workflow_definitions WHERE workflow_type='item_record_review'.

When to use it

Trigger conditions

Heuristic

The not_in_active_bid precondition warns (not blocks) — items in open bid lines can still be updated, but the workflow drafts a notification to the bid owner so the customer hears about the change first. That's the standing rule: never let a customer find a spec change in the bid PDF before we tell them.

Step-by-step what happens

The 7 beats

  1. 01

    Stage NS field update

    A proposed_actions row stages with action_type=item_field_update, entity_ref=item_code, fields from inputs.proposed_changes. Allowed fields are whitelisted (displayname, salesdescription, custitem_brand, etc) — anything else is rejected at precondition.

    Writes proposed_actions
    Time ~80ms
    Kind stage_proposed_action
    Status real
  2. 02

    Invalidate item cache

    Keys item:{item_code}, item_full:{item_code}, ns:item:{item_code} are deleted so the live /item/<code> render is fresh.

    Writes HUB_CACHE KV
    Time ~40ms
    Kind kv_invalidate
    Status real
  3. 03

    Invalidate pricing cache (pattern)

    Pattern delete on pricing:{item_code}:* via KV list scan. Busts every customer-pricing cache keyed off this item.

    Writes HUB_CACHE KV
    Time ~80ms (list scan)
    Kind kv_invalidate
    Status real
  4. 04

    Regenerate spec sheet (conditional)

    If proposed_changes touched spec-relevant fields (claims, pack_size, allergens), the spec sheet PDF regenerates via the regenerate_spec_sheet chat tool.

    Writes R2 bucket specs/
    Time ~6s
    Kind chat_tool
    Status stub
    Note conditional · spec fields touched
  5. 05

    Recompute assembly cost rollups

    For each assembly that has this item in its BOM, assembly_cost_rollup recomputes. Keeps margin math current across the assembly catalog.

    Writes assembly_cost_rollup
    Time ~200ms per assembly
    Kind d1_write
    Status stub
    Note scope · context.assembly_memberships
  6. 06

    Flag dependent pricing for review

    If item-level changes could affect customer pricing (pack_size ripples to case_price), pricing_master rows touching this item flag for the next pricing review cycle.

    Writes pricing_master flag column
    Time ~50ms
    Kind flag
    Status stub
    Note scope · context.pricing_master_row
  7. 07

    Notify sales if active bid (conditional)

    If open_bid_lines is non-empty, a notification email per bid owner drafts in outbound_email_log with status=pending_review.

    Writes outbound_email_log
    Time ~80ms per owner
    Kind hitl_email_draft
    Status stub
    Note conditional · open_bid_lines present
Outcomes

What's different after the workflow runs

NS field
Updated
via HITL
Caches
Busted
item + pricing
Assembly rollups
Recomputed
per BOM membership
Sales notified
Conditional
if in active bid
Failure modes

What can go wrong and how to recover

Item not found

Precondition item_exists blocks. Mike checks the item_code (case-insensitive lookup) and either fixes the code or runs new_assembly_item if it's genuinely new.

Item inactive

Precondition item_active warns. Mike can still proceed — sometimes reactivating an item is part of the cleanup.

Field name not whitelisted

Precondition rejects with severity=block. Adding a new allowed field requires updating the contract's precondition list (and ideally an ADR).

NS push transient

Retry policy is 2 attempts with [300s, 1800s] backoff. Drainer cron picks up persistent failures within 30 minutes.

Related

Adjacent workflows + diagrams

For developers

Code paths + invariants

ConcernWhere
Workflow contractworkflow_definitions WHERE workflow_type='item_record_review'
Allowed field listprecondition: displayname, salesdescription, custitem_brand, custitem_pack_size, custitem_case_count, custitem_buyamerican, custitem_kosher, custitem_allergens, custitem_country_of_origin, custitem_storage_temp, reorderpoint, taxschedule
Data-quality triggerdata_quality.item_flagged event
Spec regen toolregenerate_spec_sheet
Reflexion tagitem_review,data_cleanup
Risk level3
Expected duration~variable (data-driven)
Triggermanual_or_event · event_type_glob=data_quality.item_flagged
// Whitelist enforcement (precondition) const allowed = new Set([ 'displayname', 'salesdescription', 'custitem_brand', 'custitem_pack_size', 'custitem_case_count', 'custitem_kosher', 'custitem_allergens' ]); if (![...Object.keys(changes)].every(k => allowed.has(k))) { throw new Error('field_not_whitelisted'); }