The Pillar 4 build — cost, capacity, consumption
The NS assembly build flow is the operational sibling of the work order lifecycle. Where the WO lifecycle tracks what NS records, the assembly build flow tracks what the platform decides before NS records anything — BOM resolution, cost rollup against current vendor costs, capacity check, and HITL authorization when the cost surface is about to move significantly.
It runs every time a build request hits the system — from an operator, a WO, or a sales-driven backorder. The first six steps happen before NS posts a build; the last four are the consumption + creation + refresh tail.
Diagram: ns-assembly-build-flow.html. One STUB: labor capacity check — there is no formal capacity calendar table yet, so the check is currently a hand-wave that returns true unless inventory is short.
Trigger conditions
- Operator manually requests N units of an assembly via NS UI.
- Open work order requires components staged for a release.
- Sales order requires assembled stock not on the shelf.
- Pillar 4 annual roll triggers a rebuild of cost rollups for all assemblies.
- Vendor cost moved — flow runs in re-cost mode (no actual build) to refresh
assembly_cost_rollup.
Authorization fires if rollup cost > $5K OR drift_pct_vs_prior > 8%. Either condition stages a row in proposed_actions — risk_level 3, action_type='assembly_build_review'.
Build 200 cases of Melt Mates — cheese cost moved
Wednesday. NYC DOE bid B5875 requires 200 cases of MM-CHEESE-MELT-22 by Friday. SO posts; allocation can't satisfy from FG; build request opens. BOM resolves: cheddar (Bongards), bread (PUB house), butter, seasoning. assembly_cost_rollup recomputes: cheese ran +9.1% WoW (CME trailing-week formula caught the spike). Total cost moves from $14.42 to $15.71 — 8.9% drift, over threshold.
HITL fires. Mike sees the card at 11:04 — with the Bongards CME table, the 35% moisture adjustment, and the drift_pct sparkline embedded. He approves at 11:07 (knows it's real; Bongards moved this week). Capacity check: STUB — returns ok unless inventory short. Components debit; the floor builds 200 cases; NS posts the build at 16:30. Assembly created; cost recalc anchors the new $15.71 number on the cost surface. Spec sheet didn't need refresh — pack and allergens unchanged.
The ten beats
-
01
Build request — manual, WO, or SO-driven
An operator, an open work order, or a customer order requiring assembled stock fires a build request. The source is recorded for downstream tracing.
-
02
BOM resolution
Pull
assembly_bomrows for theassembly_id. Validate everyline_keyexists initemsmaster, has a current cost, and has on-hand availability. Missing or zero-cost lines abort the request with an actionable error. -
03
Cost rollup — Pillar 4 logic
Refresh
assembly_cost_rollupby summing raw component cost, packaging, labor estimate, overhead allocation, and freight per pillar 4 cost-surface logic. Bongards, Cardinal, and Ace Endico items pick up their special formulas (CME trailing week, USDA drawdown, etc.). -
04
Capacity check — STUB
Confirm labor hours available and components in inventory. Components check is real (reads
inventory_balance). STUB: labor capacity is not formally tracked — there's nocapacity_calendartable, so the check returns true unless a hard inventory short forces a queue. This is acceptable today because we run a single shift, but it won't scale beyond two production lines. -
05
HITL authorization — $5K or 8% gate
If
rollup_cost > $5,000ORdrift_pct_vs_prior > 0.08, a row is staged inproposed_actionswithaction_type='assembly_build_review', risk_level 3. Mike approves at/proposed-actions.html. Below threshold, the build proceeds without HITL. -
06
Component consumption — debit inventory
Debit
inventory_balanceper BOM line for the build qty. NS posts aworkorderissue(orinventoryadjustmentfor non-WO builds). D1 mirrors negative-qty rows intransaction_lines. -
07
Build operation — the physical build
The floor produces the assembly. System-side this is the NS
buildtransaction record that links consumption (step 6) to creation (step 8). The transaction id is the durable cross-reference. -
08
Assembly created — credit inventory
Credit
inventory_balancefor the assembly item at the production location. The assembly is now allocatable for the triggering SO or for general sale. -
09
Spec sheet refresh — if claims changed
If claims, allergens, or pack format changed in the BOM since the last spec render, regenerate via the spec-sheet-pipeline workflow. Otherwise skip. Driven by a content hash on the BOM spec-relevant fields.
-
10
Cost recalc — final actuals
assembly_cost_rollupre-runs with the final actuals from steps 6 & 8.drift_pct_vs_priorsurfaces on the item entity page and the admin-dashboard cost-surface tile. The new value becomes the baseline for the next build.
What's different after the build
- FG inventory reflects the new build; components decremented.
- Cost rollup carries the new component costs forward.
- Spec sheet regenerated if BOM claims drifted.
- Drift signal feeds the cost-surface tile and any vendor cost watchers.
What can go wrong
With no capacity calendar, two parallel build requests can claim the same labor hours. Today we mitigate by running a single shift with one production scheduler (Susan). Detection: WOs that miss promised dates. Long-term fix: capacity_calendar table + per-line shift inventory.
Resolution aborts. The build request returns an error naming the missing line_key. Recovery: create the item in NS, wait for hot-tier mirror, retry.
If vendor_cost_update workflow hasn't run since the last vendor invoice, rollup carries old number. Detection: drift_pct_vs_prior unexpectedly low when invoices show a change. Recovery: trigger vendor_cost_update for the affected vendor.
Mike doesn't approve the build_review in time; production blocks. The decide endpoint emits hitl.deferred; the operator can fall back to manual NS build but loses the cost rollup audit trail.
Adjacent flows + diagrams
Code paths + invariants
| Concern | Where |
|---|---|
| BOM source | assembly_bom (D1 mirror) |
| Cost rollup | assembly_cost_rollup (Pillar 4) |
| HITL workflow | workflow_type='assembly_build_review' |
| Drift threshold | guardrails.assembly_drift_threshold (default 0.08) |
| Cost threshold | guardrails.assembly_cost_threshold (default $5,000) |
| Spec sheet regen | spec_review_queue, content_hash trigger |
| Drift surface | /item/<code> (Pages Function), admin-dashboard |
| STUB — capacity | no capacity_calendar table; check returns true |