VSM Works

Methodology

Every formula the engine applies, its definition, and where the choice was not forced. Conventions that could reasonably go another way are marked; a tool that hides those behind a confident number is not doing analysis.

No output surface computes a metric of its own.


Time

Three axes, never interchangeable (ADR-001):

Axis Meaning
Production seconds Scheduled run time only
Working days Days the stream operates
Calendar days Wall-clock days, what the customer experiences
gross            = shifts × hours × 3600
net available    = gross − breaks×shifts − planned downtime
working days/yr  = 365.25 × workingDaysPerWeek / 7 − holidays
calendar/working = 365.25 / workingDaysPerYear

A five-day week gives 1.4 calendar days per working day.

Assumption: every holiday is assumed to fall on a day that would otherwise have been worked. Reported to the user, not smoothed over.

Planned downtime is not unplanned downtime. Breaks, maintenance windows and meetings reduce available time. Breakdowns and micro-stops do not — they belong to OEE availability. Counting a breakdown in both places would charge it twice.


Demand and takt

demand per working day = quantity / period, spread over operating days
takt                   = net available / demand per working day
pitch                  = takt × pack quantity

Weekly and monthly demand is spread across operating days, not calendar days: a customer ordering 1,500 a week from a five-day plant needs 300 a day, not 214.

Takt uses unreduced available time. It expresses what the customer requires, not what the plant can manage — capability enters through capacity, below.


Yield, and why each process has its own takt

Yield loss changes how many units must be started, never a measured cycle time (ADR-004).

Demand propagates backwards from the customer, in reverse topological order:

required output(n) = Σ required input of everything n feeds
required input(n)  = required output(n) / final yield(n)

Since upstream processes must start more than downstream ships, each process has a different takt:

expected passes      = 1 / (1 − Σ rework rates returning to n)
required passes      = required input × expected passes
yield-adjusted takt  = net available / required passes

A single stream-wide takt is not a valid bottleneck test whenever yield is below 100%. This is the correction with the widest consequences in the engine.

Quantity relationships live on material connections:

upstream requirement = downstream input × quantity per × supply share

quantityPer is the bill-of-material multiplier: an assembly consuming four bushings loads the bushing feeder four times. supplyShare distinguishes converging components from alternative routes carrying the same part. When several incoming connections omit a share, convergence is assumed and printed as an assumption.

Where a stream reaches several customers, each customer may state a demandShare. A complete allocation must total 100%. If shares are absent or an imported allocation is invalid, demand is divided equally and the fallback is reported rather than silently normalised.


Cycle time and capacity

Cycle time is derived from work elements, never stored:

cycle time     = Σ element times, excluding elements that overlap machine time
per unit       = cycle time / machine count
manual content = Σ elements that are neither machine time nor overlapping it

The overlap rule matters: a gauge check performed while the machine runs does not extend the cycle and does not load an operator.

An observedCycleTime, where recorded, is compared against the derived figure. A gap above 10% is reported. It is never used as an input and never overwritten.

changeover loss   = duration × frequency per day
available for run = net available − changeover loss
capacity          = available for run / per-unit cycle time
bottleneck        ⟺ capacity < required passes

EPEI

EPEI = (products × changeover duration) / (net available − run time needed)

This is a capability, not a schedule: the shortest interval over which the process could cycle through its mix. epeiTargetDays holds the policy. The gap between them is the size of the prize from SMED, and it is only visible because the two are separate. Undefined when demand already consumes the day — then there is no interval, only a deficit that the capacity check reports.


Quality

Stored as counts, never percentages:

total = first-pass good + rework + scrap        (rework recovered ⊆ rework)

first pass yield = first-pass good / total
final yield      = (first-pass good + recovered) / total
scrap rate       = (scrap + unrecovered rework) / total
RTY for one SKU  = Π first pass yield over the processes on that SKU's route
stream RTY       = Σ (SKU mix share × SKU-route RTY)

Convention: OEE's quality factor uses final good count, so units recovered by rework count as good. Where the count point sits decides this, which is why firstPassYield and oeeQualityRate are both reported and never substituted for one another.

RTY multiplies first-pass yields: a unit that needed rework did not go through right the first time, however good it ended up. A repair-only process is not multiplied into every shipped unit: its volume is already represented by the originating defect and rework loop. Optional operations are applied only to the SKUs that actually use them.


Handoffs, and why %C&A is not a yield

The measure an office or service stream turns on. Also counts, never a percentage:

%C&A            = usable as received / received
rolled %C&A     = Π %C&A over the processes that measured it

usableAsReceived is the portion that needed nothing added, corrected or clarified before work could start.

It is never multiplied into rolled throughput yield (ADR-022). A yield says what this process did to the work; %C&A says what the process before it handed over. A file arriving without a policy number is not scrap and was not reworked — it is returned, chased and started late, and every hour of that is spent by people the yield figure never looks at. One number covering both leaves whichever team reads it looking in the wrong place.

The rolled figure skips processes that measured nothing rather than treating them as perfect, and publishes how many it skipped against how many are in scope: a product over two of nine handoffs is a different claim from one over all nine, and the headline cannot tell them apart. A map that measured none reports no figure at all — a stream nobody asked the question of is not a stream with perfect handoffs.


OEE

availability = run time / planned production time     (or the stated uptime)
performance  = (ideal cycle time × total count) / run time
quality      = final good / total
OEE          = availability × performance × quality
A×Q score    = availability × quality                 (performance unknown)

Three factors, or a score that says it is not OEE. Where a process has no equipment record — as office and service processes do not — nothing is produced and the caller is told why. Where the record exists but no ideal cycle time or run time does, availability × quality is reported with isTrueOee: false and must be labelled as an A×Q score. The predecessor reported that product under the name OEE; the objection was always to the name, not to the number, and a process is not at 0% OEE merely because nobody has agreed its ideal cycle.

Convention: availability may be measured or stated, and the two are not equal claims. Planned time against run time is preferred wherever both exist: it feeds the performance factor and its difference is a quantity of lost time somebody can argue with. A plant that holds uptime only as a percentage — the common case, and the form Learning to See itself publishes it in — may state it directly. A stated ratio carries no period, so it is read against that process's own working day, and the changeover correction below applies to it unchanged. availabilityOf resolves the two in one place so that capacity and the OEE panel cannot disagree about which was used.

A performance factor above 1 means the recorded ideal cycle time is understated. It is capped at 1 and reported, rather than clamped into something that looks plausible.


Lead time

Lead time is the longest path, not the sum of everything on the map.

Parallel branches run concurrently: a sub-assembly line alongside the main line does not add its queue to the customer's wait. Longest-path relaxation in topological order, which is why the primary flow must stay acyclic (ADR-002).

Dwell time per node:

Node Contribution
Inventory quantity / local node demand per working day, on the production axis
Process unit residence time + average batch release wait + standard WIP wait
External process turnaround time
Material edge transport time
unit residence time = cycle time × mix factor      (machines do NOT divide it)
PCE                 = value-added time / total lead time

Residence, not interval (ADR-026). Four desks working a claim each deliver one every 300 s and hold each claim for 1 200 s. The first figure sizes capacity; the second is what the customer waits through, and it is the one the timeline charges. ProcessMetrics.effectiveCycleTime and unitResidenceTime are both published for exactly this reason, and they are equal wherever a process has one machine — which is every process on the Acme benchmark.

Value-added time is mix-weighted on the same basis, so it is a part of process time rather than a figure computed against a different denominator.

Accumulation happens entirely in production seconds; conversion to working and calendar days happens once, at the end, through the calendar.

For a process or transfer batch of Q pieces:

average batch release wait = ((Q − 1) / 2) × effective cycle time

This is the post-processing wait for a completed piece to leave with its transfer group. Upstream batch formation belongs in an explicit inventory node, so it is not counted a second time. Batch wait is reported separately from touch time and included in queue time and total lead time.

For a process holding standard WIP:

standard WIP wait = standard WIP × effective cycle time

Little's Law inside the box: a piece arriving at a station holding two others waits for both to clear. Charged here and nowhere else — standard WIP is stock inside the process, so a map that also drew a triangle for it would bill the same pieces twice. Reported separately and included in queue time, like batch wait, because the two are removed by different work.

Inventory uses the throughput propagated to its own node, including quantityPer and branch shares. Four bushings per finished assembly therefore turn 1,200 bushings into one day of supply at 300 assemblies/day, not four.


Line balance

process operator load = manual work content × required process passes / process available time
required operators    = Σ process operator loads
balance efficiency    = required operator equivalents / assigned operators   (uncapped)

Balance efficiency is uncapped, and above 1 means short-staffed. It was clamped into [0, 1], so an office needing 5.3 operator-equivalents from four people reported a comfortable 100% while the staffing plan beside it said two short. Same reasoning as capacity utilisation: the bar in the interface may stop at full, the figure may not. Note also that this is a staffing ratio and not the classical line-balance formula (work content over stations × bottleneck cycle); both are called balance efficiency in the field.

Manual content excludes unattended machine time and work hidden inside it — which is why this cannot be computed from a station's cycle time alone. Required passes include routing share, yield loss and rework. The design layer reports a range: ceil(total operator equivalents) is the theoretical minimum if work can be shared, while Σ ceil(process operator load) is the dedicated coverage case. Neither is presented as proof that labour can be removed; skill, distance, safety and simultaneous-attendance constraints require a Yamazumi study and floor verification.


Consistency checks

The engine checks the model against itself and reports contradictions rather than resolving them silently.

Little's LawWIP = throughput × flow time. Lead time is the longest path, so it excludes stock on non-critical branches; declared WIP includes it. The gap is therefore informative, not circular: it quantifies inventory parked outside the path that governs delivery. Reported above 5%.

Capacity — every process must be able to make what the customer needs.

Pacemaker — exactly one process should be declared, it should agree with the upstream end of the final continuous-flow segment, and information flow should not directly schedule multiple production processes.

Boundaries — a stream that does not start at a supplier and end at a customer has a lead time that excludes inbound and outbound material.

Charter — whether the study records why it exists and what would count as success (ADR-025). Three failing outcomes: no charter at all, goals that state no target, and measurable goals with no business case or problem statement behind them. The engine computes nothing from a charter and checks it anyway, because the failure it prevents is not arithmetic: a study without one widens until the map describes a plant rather than answering a question.

Measurement coverage — the share of inputs backed by an observation, system record or engineered standard rather than an estimate. The editor records the source and can additionally store sample size, measurement date, measurer and an evidence note. Two maps can report the same lead time to three decimals while one came from time studies and the other from recollection.


Future-state design

Sizing, not drawing. Each figure below is closed-form and reports the basis it was computed from, because a supermarket sized from a plant's own stated interval and one sized from a default are different kinds of claim.

Design policy — safety and buffer factors, service level, tolerated downtime, fallback replenishment cover and fallback container size are inputs, not constants. They are supplied by the caller, defaulted visibly, and echoed back on result.design.policy so a report can print what its recommendations rest on. See ADR-007.

cycle stock      = withdrawal rate × replenishment lead time
buffer stock     = cycle stock × buffer factor
supermarket size = cycle + safety + buffer
kanban cards     = ceil(supermarket size / container quantity)

The withdrawal rate is the consuming process's required input, so yield loss and rework loading are already in it. Cards are rounded up: half a card authorises nothing.

Safety stock is sized two ways, and the result says which one it used.

Basis When Formula
derived-demand-variability demand.variabilityCv is stated and above zero z(service level) × cv × withdrawal rate × √(replenishment days)
policy-factor no CV is stated cycle stock × safety factor

Assumption — stated because it is the kind that hides. Deriving safety stock from a coefficient of variation commits to a distribution, and this one commits to the normal: demand over the replenishment interval is treated as normally distributed about its mean, with daily draws independent, so the standard deviation over n days grows as √n. That is reasonable for aggregated repeat demand and poor for lumpy or intermittent demand — a spare-parts stream with long quiet stretches will be under-covered by this formula, and its user should override the service level or leave the CV out and size by policy instead. The engine reports the multiplier it used (safetyFactorUsed) next to the figure so the assumption can be argued with rather than only accepted.

The service level is the plant's tolerance for running out, not a property of the map, so it lives in DesignPolicy alongside the other decisions (ADR-007). The quantile is Acklam's rational approximation, written out rather than imported, and pinned in the tests against published standard-normal values.

A zero in the CV field is treated as no measurement, not as a customer with no variation. The latter does not exist, and reading it literally would print a supermarket with no safety stock at all as though that were a finding.

Kanban type — a pull link carries one of three signals, and they do not size the same store.

Kind Meaning Store
withdrawal authorises the consumer to take from the store continuous cover
production instructs the supplier to replace what was taken continuous cover
signal orders a batch once the store falls to a trigger point trigger point + batch

A signal kanban is a reorder point rather than a continuous loop, because a process with a long changeover cannot replenish one container at a time. Its trigger point is cycle stock + safety stock — demand over the replenishment interval, plus the cover held against variation — and the store peaks at that level plus the batch the signal orders. Sizing it continuously would recommend a store its first delivery overflows.

Where a signal loop's supplying process states no batch size the store falls back to the continuous formula, and the assumption says so rather than inventing a batch. An absent kanban type reads as withdrawal, which is what every map drawn before the field existed already meant.

Replenishment lead time, in order of preference:

Basis Source
declared-epei-target changeover.epeiTargetDays on the supplying process
derived-epei the interval that process is capable of (see EPEI)
policy-default the policy value, reported as an assumption
FIFO lane capacity = ceil(tolerated downtime / consuming process takt)
pitch              = takt × pack quantity
levelling slots    = available time / pitch, divided by product mix share

Where a FIFO connection feeds an external operation and no consuming-process takt exists, stream takt is used as an explicit fallback and the basis is published with the result.

EPEI feasibilityProcessMetrics.epeiDays answers how short could the interval be; this answers does the interval we intend to run fit:

available     = net available time per day × interval days
run time      = required passes × cycle time × interval days
changeover    = product count × changeover duration
feasible      ⟺ run time + changeover ≤ available

Infeasible intervals are reported with the shortfall. Negative slack is not published as a number; it is published as feasible: false.

Planned cycle time — the cycle the cell is built to run at, which is not takt (ADR-024):

planned cycle time         = declared, or takt × planned cycle allowance
operators at planned cycle = Σ (manual content ÷ own yield-adjusted takt) ÷ allowance

A cell built to the customer's exact rhythm has nothing left for a jam, a missing part or an operator answering a question. The basis says whether the team chose the cycle or the policy allowance supplied it, and the headcount is reported next to the figure at takt rather than replacing it — the gap between them is the cost of the allowance. A declared cycle above takt is rejected rather than applied: it would report fewer operators than takt requires.

Standard WIP — the pieces a cell needs in order to run:

recommended = machine count, where any element runs unattended
            = 0,             where none does

One piece in each machine that cycles on its own while the operator walks on. Anything above that minimum is a queue inside the cell with a standard-work name on it, and is reported in pieces — true wherever the cell sits, unlike days, which depend on the critical path.

Product strategy — which products to hold and which to build when asked (ADR-023):

Classification When (unclassified products only) Recommended fulfilment
runner mix share ≥ runner threshold make to stock
repeater between the two thresholds none — a judgement
stranger mix share < repeater threshold make to order

A plant's own classification is preferred to the engine's reading of volume, and the basis says which was used. How often a product is actually ordered decides this and no map records it, so where share was used the assumption says so and prints both thresholds. A repeater gets no recommendation: shelf life, contract terms and changeover cost decide it, and the model holds none of the three. A single-product stream gets nothing at all.

Pacemaker — walk upstream from the last process for as long as material moves directly, with no buffer to sit in and no pull signal to wait for. The upstream end of that segment is where the schedule belongs. The recommendation is reported next to what the map declares; it never overwrites it.


Diagnostic rules

Named for what it does. The prototype called the same idea a "root cause engine" while mapping a symptom to a fixed sentence, with no downtime classification, Pareto or correlation behind it. See ADR-008.

Every finding carries the rule that fired, the metric compared, the threshold crossed, the value observed, a confidence level, a verification step, and an impact that is either quantified in a stated unit or explicitly none.

Rule Fires when Default threshold
capacity-shortfall capacity < required passes
capacity-buffer-risk load leaves less than the policy capacity buffer 15% buffer
cycle-time-above-takt cycle time > yield-adjusted takt
changeover-loss changeover share of the day 10%
epei-above-target achievable EPEI > stated target
excess-inventory days of supply at a buffer 2 days
inventory-capacity-exceeded quantity > declared physical/control limit
low-first-pass-yield first pass yield 95%
low-complete-and-accurate share of arriving work usable as received 90%
low-process-cycle-efficiency PCE 5%
push-scheduling share of material links on push 80%
pacemaker-mismatch declared and recommended schedule points differ
kanban-sizing-mismatch declared cards differ from calculated cards 15%
standard-wip-above-minimum in-process stock above what the sequence needs
product-strategy-mismatch declared fulfilment contradicts the classification
fifo-sizing-mismatch declared FIFO limit differs from calculated cover 15%
line-imbalance balance efficiency 85%
incomplete-equipment-data a process with no availability record
estimate-heavy-data share of inputs that are measurements 70%

Thresholds are judgements about a plant, not constants: a job shop and a high-volume line disagree about what counts as excess inventory. All of them are overridable, and the set actually used comes back on the report.

Confidence is downgraded one step on a map whose data confidence is below threshold — except for the two findings that are about data quality, which would otherwise argue themselves down.


Use in production-investment decisions

The engine can support the operational side of an investment decision: demand and yield-adjusted capacity, capacity gap and buffer, shared-resource load, required operator-equivalents, batch delay, inventory exposure, current/future comparison and the measurement confidence behind those figures.

The model carries no money. There is no unit cost, no labour rate, no inventory carrying rate, no changeover cost and no capital cost anywhere in the schema or the engine. Every output is a physical quantity — pieces, days, seconds, operator-equivalents, cards — and converting any of them into a figure a finance function will recognise happens outside this tool, in a model it cannot see and therefore cannot check.

Three consequences worth stating plainly, because each is easy to assume away:

  • Inventory exposure is pieces and days, not working capital. A supermarket of 686 pieces is not a number of lira until someone supplies a unit value, and the engine will not notice if the value used is wrong.
  • Improvements cannot be ranked by return. The rules engine orders findings by severity and quantified physical impact. It has no view on which of two findings is worth more, because it cannot price either.
  • A current/future comparison is not a business case. MetricDelta says a lead time fell and by how much; whether that fall justifies the equipment that produced it is a question the deltas do not contain.

This is a scope decision rather than an oversight, and it is revisitable: cost rates would enter as policy and unit values as map data, in the manner of ADR-007. Until they do, an export is an operational input to a business case, never the business case.

It does not turn a VSM into an automatic capital-approval model. Before authorising equipment or labour from these outputs, the decision record should also contain:

  1. a dated demand baseline plus low/base/high demand scenarios;
  2. observed cycle-time distributions and downtime history, not only averages;
  3. demonstrated quality/rework routing and batch/transfer rules;
  4. physical constraints, skills, safety and simultaneous staffing needs;
  5. supplier and external-process service evidence;
  6. CAPEX/OPEX, implementation time, working-capital effect and finance-approved NPV/payback assumptions;
  7. a named owner for every estimate and a floor-verification sign-off.

Findings deliberately include a verification step and quantified impact is none where the model cannot defend a number. In particular, the gap between assigned people and theoretical operator-equivalents is not claimed as labour savings until work sharing has been demonstrated.

Quantified impact is deliberately conservative:


Verification

The engine's reconstructed Acme Stamping current-state benchmark matches three published totals from Rother & Shook, Learning to See:

Figure Published Computed
Takt time 60 s 60 s
Processing time 188 s 188 s
Production lead time 23.6 days 23.62 days

It also matches the example's central finding — assembly 1 at 62 s cannot meet a 60 s takt — and declines to report OEE, because the book's "uptime 85%" is not the three-factor measurement OEE requires.

Provenance. The fixture was reconstructed from the book's published totals rather than transcribed from a copy in hand, which made the benchmark circular: inputs chosen to reproduce an output cannot independently confirm that output.

On 2026-07-30 the reconstruction was cross-checked field by field against three independent teaching reproductions of the same current-state map. Every figure is corroborated — the five cycle times (1 / 39 / 46 / 62 / 40 s), the five inventory quantities (4,600+2,400 · 1,100+600 · 1,600+850 · 1,200+640 · 2,700+1,440), five days of coils, 18,400 per month split 12,000 LH / 6,400 RH over 20 days, the one-hour stamping and ten-minute weld changeovers, and two eight-hour shifts with two ten-minute breaks each.

Two sources disagreed, and both disagreements fail on arithmetic rather than on authority: spot-weld times of 45 s and 50 s sum to 198 s, not the published 188 s; and repeating 1,600+850 after assembly 1 gives 24.28 days, not 23.6. The corroborated set is the only one consistent with the published totals.

The sources also publish uptimes (85 % stamping, 100 % weld 1, 80 % weld 2, 100 % both assemblies) as bare percentages, with no planned time, run time or ideal cycle time behind them. The model can now hold a bare percentage as a stated availability, so the omission is a choice rather than a limitation: the fixture still omits it, because putting it in would move the benchmark's capacity figures away from the published totals this fixture exists to reproduce. The engine still declines to report OEE for it.

Weld changeover frequency remains an assumption: the book states every-part-every-two-weeks for stamping only, and no reproduction supplies the weld figures. It affects capacity, not any asserted golden figure.

This is corroboration by secondary sources, not verification against Rother & Shook. The remaining gap is narrow but real, so the note stays.

This is an accepted limitation, not an open task. Closing it needs a copy of the book, which the project does not have; no further work in this repository can narrow the gap, and the claim made in the README is worded to the evidence that exists. Anyone with the book in hand can check the fixture field by field against the figures listed above — that is the whole of what remains, and it is recorded here rather than tracked as work in progress.

Sources consulted: Arrizabalagauriarte Consulting · MapMyOps · SlideShare VSM deck

Open the editor