HITL Writeback to NetSuite

Chat tool → proposed_actions → Mike approves (R560: requires X-Edit-Token) → ns_pending_pushes (R367+R378 atomic claim, 10-min lease-reclaim race fix) → NS_PUSH_QUEUE → NetSuite RESTlet (TBA OAuth1)

Propose Human approval Push to NS Audit + mirror raise a price · attach PDF · update vendor council selects propose_price_change INSERT pending · entity_ref · payload action_id status: pending · review /api/proposed-actions show pending in admin-dashboard.html POST /decide {approve} · X-Edit-Token UPDATE status='approved' enqueue push row send(NS_PUSH_QUEUE) consumer: POST RESTlet · TBA OAuth1 200 · ns_record_id UPDATE status='applied' · ns_id mirror applied row (R379) User chat surface Chat council v2 propose_* tool HITL tool template proposed_actions pending queue Mike loop step · admin /decide /api/proposed-actions/:id/decide ns_pending_pushes drain queue NS_PUSH_QUEUE CF Queue NetSuite RESTlet write Legend request return security async trace

Mike is the loop step

  • • Every NS write needs HITL · standing invariant
  • • X-Edit-Token required on /decide
  • • Approval is auditable (chat_decision_audit)
  • • Direct writes that bypass HITL mirror back into proposed_actions (R379)

Tool families that propose

  • • propose_price_change · propose_vendor_item_match · propose_action_*
  • • matches the HITL TOOL TEMPLATE in src/index.ts (~line 3947)
  • • tool returns action_id; never writes to NS directly
  • • 5 propose_* tools added this session (Phases 14-19)

Queue + drain semantics

  • • ns_pending_pushes is the durable drain table
  • • NS_PUSH_QUEUE = CF Queue with DLQ + retries
  • • Consumer hits NS RESTlet under TBA OAuth1
  • • Applied rows update both pend + proposed_actions

Safety net

  • • PushMutexDO prevents concurrent pushes per entity
  • • CostCapDO caps per-day AI + NS spend
  • • Audit log writes to chat_decision_audit
  • • Failed pushes surface in /api/proposed-actions + admin dashboard