Skip to main content

cwright lint

cwright lint <model> [--json]

Asks whether what the document describes is possible — and says so without refusing. validate answers is this document well formed; lint answers can this model run at all, which is a different question with a different remedy. A step naming a resource that does not exist is a typo. A tool group the route data demands 112% of is a decision somebody has to make.

It computes four things from the route data alone, with no simulation:

checkwhat it compares
offered-loadthe work each resource is asked for, against servers × capacity × availability
operator-shiftthe person-seconds each set of interchangeable pools is asked for, against its headcount
batch-fillhow long a lot waits for company, against the whole of its own route
release-ratethe declared release rate, against what the bottleneck sustains
unfed-storea consumable a step draws from that starts empty (initial: 0), never reorders and that no step produces — every entity reaching it waits for ever, and the line has no bound

A model path of - reads the document from stdin.

It warns, and never refuses​

lint exits 0 whatever it finds. A transient overload is a legitimate thing to model — a fab deliberately over-released to see what happens is a normal experiment — and a check that blocks gets switched off. validate is the command that refuses.

Why the arithmetic and not the run​

A simulation cannot tell you how much a resource was over-asked, because a saturated server cannot report more than 100% busy. The over-release comes out somewhere else: as arrivals turned away, as a queue that grows all run, or as an upstream tool blocked.

examples/wafer-fab.yaml is the clearest case, because the fix ships beside it:

litho offered loadlitho Idle%litho mean queue
wafer-fab.yaml⚠️ 100.11%0.0075.13
wafer-fab-3-scanners.yaml66.74%20.373.10

Its Processing is only 80.23% in the first row — the rest of the tool's time is downtime — so no utilisation figure in any results document could have said 100%. The arithmetic can.

⚠️ The engine columns are one replication (simulate --replication 1); the point they make is the shape, not the third digit.

Every reading is the favourable one​

Each term takes the interpretation most generous to the model, so anything still flagged is infeasible under every reading:

  • a batch step is charged one load's worth of tool time divided by the largest number of lots a load can hold, not one lot's worth;
  • maintenance and breakdown come out of the availability multiplicatively, which is the highest availability the two can jointly leave;
  • a batch group's wait is measured against the longest route among its members;
  • a batch group's minimum is the smallest any member declares;
  • changeover time is charged as zero. A perfectly campaigned tool never changes recipe, so zero is the favourable reading — and how often a tool actually changes over is a dispatch outcome rather than something the document states. ⚠️ It is not small: measured on SMT2020's HVLM, Implant_91 spends 10.99% of its life in Setup, Implant_128 10.39% and LithoTrack_FE_95 6.82%. So a group this reports at 0.92 may really need 1.03, and the offered load is a lower bound wherever changeovers or min_run are declared.

Three terms were missing before the arithmetic worked, and each was found by refusing to believe a number that cannot be true of a fab that demonstrably runs:

  • a step's probability is the share of lots that visit it at all — metrology is sampled, and charging every lot reported 396.95% on a fab that runs;
  • maintenance has to be in the availability, and it is most of the gap the first hand calculation found;
  • a usage maintenance trigger counts visits, not pieces. Counting pieces is 25× too large on a 25-wafer lot, and it drove 71 of 106 tool groups to zero availability.

Output​

wafer-fab (43570174d106f9ee)

resource slots avail offered load
litho 2.0 0.881 1.7639 100.11% <-- at or above capacity
etch 2.0 0.904 1.0820 59.83%
...

3 warning(s) -- this is not a refusal:
offered-load litho: the route data demands 100.11% of it: 1.7639 slot-seconds of work per
second against 1.7620 slots (2 x availability 0.881)
release-rate logic: the bottleneck is litho at 100.11%, so this stream is 1.00x what the
fab sustains: one lot every 5406 s would fit where it asks for one every 5400 s
release-rate memory: the bottleneck is litho at 100.11%, so this stream is 1.00x what the
fab sustains: one lot every 6407 s would fit where it asks for one every 6400 s

The table is printed even when nothing is flagged, because the useful answer to "can this run?" is usually "yes, and here is the bottleneck".

--json emits the same thing as a document: resources, pools, batches and findings, each carrying the numbers rather than the sentence. An infinite ratio — nothing feeds this batch group — is written as the string "Infinity", because JSON has no spelling for it.

What it does not compute​

A closed population has no release rate, so the offered-load question does not apply to it: a conwip model is capacity-limited by construction, and lint says so rather than reporting 0%. The same goes for a model that releases nothing at all. In both cases the reason is printed, because an empty table and a table of zeroes read the same and neither means fine.

Three more things are outside it, and they are outside it silently — so they are listed here rather than discovered:

  • changeover time, for the reason above. The offered load is a lower bound on any resource that declares changeovers or a campaign minimum.
  • consumable supply. A store whose replenishment cannot keep up with the draws against it is one division away — and it is not done. examples/gas-station-tank.yaml with its reorder quantity at 3,000 units and an 18,000-second lead time supplies 0.167 units a second against a demand of 0.706, 4.2× over, and lint prints the same table it prints for the healthy model and for gas-station.yaml, which has no tank at all. The engine's answer for that document is 5,079 lots completed of 6,742 released, with 6,198 stockouts.
  • a scheduled lot before the measured window. Work that arrives and clears during warm-up is not work the window has to do, which is the whole reason warm-up exists. SMT2020's 2,256 work-in-progress lots all sit at time zero and therefore contribute nothing.

When to use it​

Between validate and run, on any document a script or an agent generated. It costs no simulation, and the four questions it asks are the ones that produce a model which runs, reports plausible numbers, and is wrong.