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 Law — WIP = 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
ndays 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
DesignPolicyalongside 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 feasibility — ProcessMetrics.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.
MetricDeltasays 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:
- a dated demand baseline plus low/base/high demand scenarios;
- observed cycle-time distributions and downtime history, not only averages;
- demonstrated quality/rework routing and batch/transfer rules;
- physical constraints, skills, safety and simultaneous staffing needs;
- supplier and external-process service evidence;
- CAPEX/OPEX, implementation time, working-capital effect and finance-approved NPV/payback assumptions;
- 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:
- changeover — only the internal setup share, the part SMED converts
- excess inventory — days above the threshold, an upper bound, since only stock on the critical path governs delivery
- cycle time above takt, low PCE, push scheduling —
none. They are real findings without a defensible number, and inventing one would be worse.
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