Inventory reconciliation (cycle count) risk 3 · mediumcronreflexion on

workflow_type: inventory_reconciliation · owner: mike · contract v2 · source diagram: ns-inventory-reconciliation.html

Weekly per-zone cycle count: count zone → diff to D1 inventory_balance → HITL adjust if variance > threshold → NS inventoryadjustment push → recompute cost basis. HITL gated for any zone with variance > $500 OR > 10% of zone inventory.

0 · Visual flow Inventory reconciliation (cycle count) — 10 fan-out targets, 3 verify checks

idle
NS inventory reconciliation — cycle count schedule → physical count → variance detection → threshold check → HITL stage → Mike approves → NS push → D1 mirror update → audit trail → variance report 01 / Schedule 02 / Count 03 / Variance 04 / Threshold 05 / HITL 06 / Approve 07 / NS push 08 / Mirror 09 / Audit 10 / Report CYCLE COUNT SCHEDULED — Weekly cron per warehouse zone selects a count list. Cron rotates zones so every SKU is counted within 30 days. CRON schedule: 0 6 * * MON (weekly Monday 06:00 UTC) rotation: zone_A · zone_B · zone_C · zone_D TABLES read: locations · cycle_count_schedule STATUS: REAL cycle count cron schedule weekly per zone MESSAGEBUS · CF Cron i PHYSICAL COUNT — Warehouse staff walks the zone and records counts. Currently captured on paper or via NS UI mobile; barcode scanner integration is STUB. ACTION capture: physical_qty per item × location SOURCE paper: walk-sheet typed in NS UI mobile: NS mobile inventory count form STATUS ns_native: REAL scanner_autoflow: STUB physical count warehouse staff walk and count EXTERNAL · STUB scanner i VARIANCE DETECTION — Diff physical_qty vs inventory_balance.quantityonhand per item × location. Compute variance_pct and variance_abs (absolute units and dollar value). ACTION variance = physical - on_hand variance_pct = variance / on_hand variance_value = variance × item.avg_cost TABLES read: inventory_balance · items (cost) write: cycle_count_variances (new) STATUS: REAL variance detect physical − on-hand pct + abs + value BACKEND · D1 compute i THRESHOLD BRANCH — If |variance_pct| ≤ 2% AND |variance_value| ≤ $100, auto-adjust. Otherwise route to HITL. Threshold configurable via guardrails table. THRESHOLD auto_adjust: |pct| ≤ 2% AND |$| ≤ $100 hitl_route: anything larger TABLES read: guardrails.inventory_auto_pct STATUS: REAL threshold ≤ 2% auto ≤ $100 auto else → HITL BACKEND · branch i HITL STAGE — proposed_action row with action_type='inventory_adjustment'. Payload contains item_code, location, on_hand, physical_qty, variance, suggested_reason. ACTION insert: proposed_actions (pending) HITL surface: /proposed-actions.html action_type: 'inventory_adjustment' risk: 3 TABLES write: proposed_actions STATUS: REAL HITL stage proposed_actions inventory_adjustment SECURITY · risk 3 i MIKE APPROVES — Admin reviews variance and reason at /proposed-actions.html. X-Edit-Token required. Approval flips proposed_action.status to 'approved'. ACTION status: pending → approved add: approved_by, approved_at, reason_note HEADER X-Edit-Token required TABLES write: proposed_actions (status flip) STATUS: REAL Mike approves X-Edit-Token /proposed-actions SECURITY · HITL i NS PUSH — Approval drops a row in ns_pending_pushes targeting inventoryadjustment record_type. PushMutexDO drains and writes via NS RESTlet OAuth1. ACTION enqueue: ns_pending_pushes drain: PushMutexDO → NS RESTlet ns_record: inventoryadjustment TABLES write: ns_pending_pushes ENDPOINT push: NS_PUSH_QUEUE drainer STATUS: REAL NS push ns_pending_pushes inventoryadjustment CLOUD · PushMutexDO i D1 MIRROR UPDATE — inventory_balance.quantityonhand reflects new value. Reservation rows recomputed. Sync engine confirms NS parity on next 5-min sync. ACTION set: inventory_balance.quantityonhand = physical_qty recompute: quantityavailable TABLES write: inventory_balance STATUS: REAL D1 mirror qty_on_hand updated available recomputed DATABASE · D1 i AUDIT TRAIL — reflexion_log row written with reason + delta + approved_by. events.inventory.adjusted fires onto the event ledger. ACTION insert: reflexion_log (tags=inventory_adjustment) fire: events.inventory.adjusted TABLES write: reflexion_log · events SUBSCRIBERS customer_health_predictor · ar_aging_view STATUS: REAL audit trail reflexion_log events.inventory.adjusted downstream listeners DATABASE · event ledger i VARIANCE REPORT — admin-dashboard tile surfaces last 30 days of variances by zone, item, value. Patterns inform next cron schedule. SURFACES admin-dashboard.html (inventory tile) /inventory/variances TABLES read: cycle_count_variances · reflexion_log STATUS: REAL variance report admin-dashboard 30-day rolling FRONTEND · tile i if ≤ 2% AND ≤ $100 → bypass HITL, auto-adjust D1 + NS LEGEND Cron External capture Backend HITL Push (NS) D1 / ledger Surface

1 · Trigger FIRES WHEN…

kind
cron
schedule (cron)
0 6 * * MON
description
Weekly per-zone cycle count, every Monday 06:00 ET

2 · Inputs required

namerequiredtype / hint
zone_idrequiredinteger
counted_atrequiredstring
countsrequiredarray

3 · Context loaded D1 queries run before fan-out

name
zone
tables
inventory_zones
returns
row
SELECT
  id, name, location_id
  FROM inventory_zones
  WHERE id = ?
name
current_balances
tables
inventory_balance · inventory_zones
returns
rows
SELECT
  item_code, quantityavailable, last_counted_at
  FROM inventory_balance
  WHERE location_id = (SELECT location_id
  FROM inventory_zones
  WHERE id = ?)
name
recent_movements
tables
transactions · inventory_zones
returns
rows
SELECT
  item_code, type, qty, trandate
  FROM transactions
  WHERE trandate >= datetime('now','-7 days')
  AND location_id = (SELECT location_id
  FROM inventory_zones
  WHERE id = ?)
name
variance_tolerance
tables
guardrails
returns
row
SELECT
  pct_threshold, dollar_threshold
  FROM guardrails
  WHERE name = 'inventory_variance'

4 · Preconditions checked before any fan-out

checkruleseverity
zone_existszone_id IN (SELECT id FROM inventory_zones)block
counts_non_emptylength(counts) > 0block
counted_at_recentcounted_at >= datetime('now','-24 hours')warn
no_pending_movementsNOT EXISTS (SELECT 1 FROM ns_pending_pushes WHERE zone_id=? AND status='pending')warn

5 · HITL gate

Risk level 3 ≥ 3 — runner stages a proposed_actions row before fan-out runs. Mike must approve in proposed-actions.html before any side-effect step executes (real or stub).

action_type
workflow_inventory_reconciliation (proposal envelope)
entity_ref
workflow:inventory_reconciliation:run_<run_id>
approver
mike (single-admin)

6 · Fan-out targets 10 total · 3 real · 7 stub

#1compute_variance d1_write STUB

table
inventory_count_log
operation
insert
stub — not yet implemented in src/lib/workflow_runner.ts (kind d1_write hits the placeholder branch). Documented intent only.
INSERT INTO inventory_count_log (zone_id, item_code, counted_qty, system_qty, variance, counted_at)
  VALUES (?,?,?,?,?,?)

#2classify_variance flag STUB

table
inventory_count_log
field
classification
value
needs_review
condition (if)
abs(variance) > tolerance.pct_threshold OR abs(variance_dollar) > tolerance.dollar_threshold
stub — not yet implemented in src/lib/workflow_runner.ts (kind flag hits the placeholder branch). Documented intent only.

#3stage_adjustments stage_proposed_action REAL

action_type
inventory_adjustment
entity_type
inventory_zone

#4hitl_approve stage_proposed_action REAL

action_type
inventory_adjustment_approval
entity_type
workflow_run

#5ns_push_adjustments ns_push STUB

NS record_type
inventoryadjustment
queue
NS_PUSH_QUEUE
on_failure
retry_3_then_alert
stub — not yet implemented in src/lib/workflow_runner.ts (kind ns_push hits the placeholder branch). Documented intent only.

#6d1_update_balances d1_write STUB

table
inventory_balance
operation
update
stub — not yet implemented in src/lib/workflow_runner.ts (kind d1_write hits the placeholder branch). Documented intent only.
UPDATE inventory_balance
  SET quantityavailable=?, last_counted_at=datetime('now')
  WHERE item_code=?
  AND location_id=?

#7kv_invalidate_inventory kv_invalidate REAL

keys
inventory:zone:?zone_id
inventory:summary

#8variance_summary_notify hitl_email_draft STUB

tool
propose_email_to_customer
mailbox
warehouse@globalfoodsolutions.co
template
weekly_variance_summary
stub — not yet implemented in src/lib/workflow_runner.ts (kind hitl_email_draft hits the placeholder branch). Documented intent only.

#9recompute_cost_basis chat_tool STUB

tool
recompute_assembly_cost_rollup
condition (if)
any_adjusted_item IN assembly_bom
stub — not yet implemented in src/lib/workflow_runner.ts (kind chat_tool hits the placeholder branch). Documented intent only.

#10reflexion_write d1_write STUB

table
reflexion_log
operation
insert
stub — not yet implemented in src/lib/workflow_runner.ts (kind d1_write hits the placeholder branch). Documented intent only.
INSERT INTO reflexion_log (workflow_run_id, entity_type, entity_id, outcome, tags)
  VALUES (?,'inventory_zone',?,?,'inventory,cycle_count,variance')

7 · Post actions declared + runner-automatic

idactionsource
runner_log_runINSERT into workflow_run_log (run_id, workflow_type, status, started_at, completed_at, summary_json)runner automatic
runner_reflexionINSERT into reflexion_log (tags=inventory_reconciliation, run_id, narrative)runner automatic (reflexion_enabled=1)
log_runINSERT workflow_run_logdeclared in contract
reflexionINSERT reflexion_log with tags=inventory,cycle_countdeclared in contract
event_completedFIRE event workflow.completed (workflow_type=inventory_reconciliation)declared in contract

8 · Verify checks written to workflow_verify_results

name
counts_logged
when_to_run
5 min after run
expected
n > 0
SELECT
  COUNT(*) AS n
  FROM inventory_count_log
  WHERE zone_id=?
  AND counted_at > datetime('now','-1 hour')
name
adjustments_pushed
when_to_run
60 min after run
expected
n >= staged_count
SELECT
  COUNT(*) AS n
  FROM ns_pending_pushes
  WHERE record_type='inventoryadjustment'
  AND created_at > datetime('now','-1 hour')
name
d1_balances_updated
when_to_run
120 min after run
expected
n >= staged_count
SELECT
  COUNT(*) AS n
  FROM inventory_balance
  WHERE last_counted_at > datetime('now','-2 hours')

9 · Retry policy

max_attempts
3
backoff
exponential
base_ms
2000
max_ms
60000
alert_on_final_failure
true

10 · What changes when this workflow runs aggregated side effects

systemtable / resourceactionstatussource
D1proposed_actionsINSERT (action_type=inventory_adjustment)REALfan-out #3 (stage_adjustments)
D1proposed_actionsINSERT (action_type=inventory_adjustment_approval)REALfan-out #4 (hitl_approve)
KV (CACHE)inventory:zone:?zone_id, inventory:summaryinvalidateREALfan-out #7 (kv_invalidate_inventory)
D1workflow_run_logINSERT (run summary)REALrunner automatic
D1reflexion_logINSERT (tags=inventory_reconciliation)REALrunner automatic
Eventworkflow.completed (or workflow.failed)fireREALrunner automatic
D1workflow_verify_resultsINSERT pending × 3REALrunner verify staging
D1proposed_actionsINSERT (HITL gate envelope)REALrunner HITL gate
D1inventory_count_loginsertSTUBfan-out #1 (compute_variance)
D1inventory_count_logset classification=needs_reviewSTUBfan-out #2 (classify_variance)
NetSuite (via NS_PUSH_QUEUE)inventoryadjustmentpushSTUBfan-out #5 (ns_push_adjustments)
D1inventory_balanceupdateSTUBfan-out #6 (d1_update_balances)
D1proposed_actionsINSERT (email draft via propose_email_to_customer)STUBfan-out #8 (variance_summary_notify)
Chat toolrecompute_assembly_cost_rollupinvokeSTUBfan-out #9 (recompute_cost_basis)
D1reflexion_loginsertSTUBfan-out #10 (reflexion_write)