← back to pin listM-code glossary — RECEIVED, and Jordan has ruled on every code
kerfmaster pin list · Waiting on the shop
questionmixedclosed d13Unresolved, waiting on Aristide or Jordan.
Content last changed 2026-08-04 — computed from the item itself, not typed.
Contract — Post stage
This contract is unresolved — the gate below is the thing waiting on an answer.
takes —
makes machine-profile
fails if An M-code emitted whose meaning we inferred rather than confirmed.
Contract last changed 2026-08-06 — computed, not typed. Dated separately from the text above, so neither date can speak for the other.
3 open questions block this pin
- Q10 Which pierce subprogram does a job call for a given material and thickness? We hardcode 9011 and there are at least 9008 and 9035 as well.
Jordan — The one thing still outstanding from the glossary, and a better question than the one it replaced. - Q11 Are the M1xx condition-select codes and the #1xx condition variables the same table?
Jordan — Flagged on the pin specifically so it is not quietly assumed. - Q12 M124/M125 corner control and M140/M141 spatter-preventing spray exist on the control and neither shop file uses them. Is that a choice, or does the machine not have the option?
Jordan — Noted from the glossary; nobody has asked.
⚠ Known defects
This item's subject has a known defect in the code. Source: cadmaster/defects.json → cadmaster/KNOWN_DEFECTS.md, not this page — the text below is generated from the register so the two can never disagree.
- D13 — The end-of-boundary M-code is keyed on cutter comp; Jordan has confirmed it must not be (CLOSED)
emit.py:1443 picks the end code as `end_mcode_comp if on else end_mcode_g40` -- M121 when a boundary is cut-critical (comp on), M87 when it is not. The control's own glossary says M87 is 'Beam off' and M121 is 'Process end'. Neither is a compensation code. The correlation we built the rule on is 90 comp-off boundaries ending M87 and 1 comp-on boundary ending M121 in the master NC -- and that one boundary is also the LAST boundary in the program, at line 1730 of 1734, which fits 'process end' at least as well as it fits 'comp on'.
Cost today: None. Fixed 2026-08-04 before any file with two top-level profiles was posted.
Verified: 2026-08-03. Code census of the master NC, the 07-29 shop file and a fresh post: all three carry exactly 90 M87 + 1 M121 + 91 M199, and M121 sits 4 lines from M30. Glossary transcribed from machine_codes.json. CONFIRMED by Jordan 2026-08-04, in his own words: "To be clear, M121 & M87 don't have anything to do with cutter comp." The defect is no longer an inference. The replacement rule is now DEFINED too: Jordan defined "subprogram" on 2026-08-04 as one part's G-code, authored from one DXF and called once per instance across a nest. So M121 ends a PART and M87 ends a FEATURE -- which is exactly the 90-to-1 split in the master. The correct rule is `M121 on the last boundary of the subprogram, M87 on every other`, with no reference to comp. Stays OPEN because the fix has not been made: it is a code change and nobody has authorised one. Output is unaffected for a single part whose outer profile is cut last, which is every job shipped so far. Jordan confirmed 2026-08-04 that the inline structure stays for now ("keep it this way for now, and we'll learn more about subprograms and nesting later"), so the fix is the small one: the subprogram is the program, M121 on the last boundary, M87 on every other. No restructuring rides along. FIXED 2026-08-04 on Jordan's go. emit.py now reads `end_mcode_last if bi == len(cons) else end_mcode_feature`, with no reference to comp state, and the kwargs are renamed from end_mcode_comp/end_mcode_g40 so the old idea cannot be re-read out of the signature. Output on the novi part is unchanged -- 90 M87, 1 M121 on the last boundary -- which is the expected result, since the part that exposed the bug does not trigger it.
Jordan, 2026-07-29: "I will look for an M-code glossary and upload when able. Put a reminder for me in the edit file." This was that reminder. Aristide supplied it on 2026-08-03 — four photographs of the control's own scrolling G-code and M-code list, taken off the machine screen. Transcribed into cadmaster/machine_codes.json; build_codes.py renders cadmaster/MACHINE_CODES.md and re-runs the census each time. The four images stay in incoming/ as the primary evidence, because a hand transcription is a copy and the photograph is not.
ANSWERED — the codes this item was built around
- M87 = Beam off. Ends the 90 interior boundaries.
- M121 = Process end. Ends the one outer boundary — which is also the last boundary in the program. See the section below; this is not the harmless answer it looks like.
- M101 = cond data 1 select. Not a mystery code at all: it selects cutting condition set 1, on every
G0G40M101 rapid to a pierce. - M199 = Height control off. Closes every boundary block, after M87/M121.
- M66 = Emission on. Once, after the material select.
- M100 = cond search. So
M100[MSO7,0.125] is a lookup into the condition table by material and thickness — which is exactly the table Jordan said the values come from (item 4a). - M98 = Sub-program calling, M99 = Sub-program return. M99 in a main program being a return supports the existing reading of it as a MetaCam artefact: the older file was shaped like a subprogram, the master is not.
The census — nothing outside the vocabulary
Every G and M word in the master NC, the 07-29 shop program and a fresh post from HEAD, comments stripped, matched against the glossary: all three use only documented codes, and all three use the same nineteen. Counts are identical across the board (90 M87, 1 M121, 91 M98, 91 M101, 91 M199, 182 G40, 1 G41) except the geometry words and the 07-29 file's lone M99 and missing G52. Re-run with python3 build_codes.py <any.nc>.
ANSWERED, AND AGAINST US — the M87/M121 pairing
This item used to ask whether the M87/comp-off and M121/comp-on pairing was causal or coincidence, and recorded that our post already bets on causal. The glossary says neither code has anything to do with cutter compensation. M87 turns the beam off; M121 ends the process. The master's single M121 is at line 1730 of 1734, four lines above M30 — the position of a program-ending code, not of a comp state. The 90-to-1 correlation we read as a comp rule is equally well explained by the outer profile simply being cut last.
Consequence: emit.py:1443 picks the end code on comp state, so any job with two comp-critical boundaries emits "Process end" twice. The default cut_critical="outer" selects every depth-0 profile, so a file holding two separate parts — or any nested sheet — already does this. Nothing shipped so far has hit it because the novi sign has exactly one outer profile and it is cut last. Registered as defect D13, open and deliberately not fixed.
Still worth one line from Jordan to confirm the reading before anyone changes the post: is M121 the end of the program, or the end of a cut?
JORDAN RULED ON ALL OF IT — 2026-08-04, in two rounds
He answered the glossary code by code, then answered the follow-ups. Everything below is settled unless it says otherwise.
- M101 — removed. DONE 2026-08-04. "Anytime we see G0G40... we are already in rapid mode, so M101 is likely an artifact from an older post." The worry that we might be dropping a condition select was put to him and answered: "#501=#107 will tell it to use line 7 in the table called out by M100." So the condition comes from the M100 table lookup plus the #501 line select, and M101 is redundant to it. "We will test, but I'm 99% sure we can eliminate M101 during rapid moves. For now, this is how we are going to operate." That also explains
#501=#107, which we have emitted on every boundary without knowing what it did. - M87 — keep. SETTLED. "It confirms that the beam is off before we rapid to the next feature." A safety interlock, which is why it is on every boundary.
- M199 — keep. SETTLED, and my reading of it was wrong. It turns off the height sensor and selects the machine's evade setting before rapid travel. This item previously said that meant the machine has its own protection against the same hazard our cut-order rule guards. Jordan: "I disagree. 'Evade' in this context is a setting that defines how far Z raises up during rapid travel. We only have around ~5″ of Z travel. It does not 'see' obstacles and therefore it cannot truly evade. We need to keep the rules as you have them now." Corrected. See item 4e.
- M66 — at the beginning of each main program. SETTLED. What we emit.
- #3002 — keep the timer in your format. SETTLED. What we emit, at the first boundary.
- M121 — not a comp code. SETTLED, and D13 is now FIXED on it. "To be clear, M121 & M87 don't have anything to do with cutter comp." Its placement is "at the end of every subprogram", and subprogram now has a definition — one part, called N times across a nest. So M121 ends a part, M87 ends a feature. Against the master that is exactly the 90-to-1 split we measured. The rule is now stated well enough to fix D13; the fix is not made.
- More than one condition set per program — yes, eventually. "We'll want to put this in the tables. For now you've only seen a few examples, you will see them in future examples and/or real life files." So M102–M113 and M714–M716 are live vocabulary for us, not dead codes.
- Which pierce subprogram — not answerable yet, and deliberately so. "We haven't given enough examples yet to cover this and we have only so far developed reasoning around 1/8″ thickness steel. We are doing this mostly to learn methodology not defining exclusive business rules yet." That last sentence is the frame for this whole item and matches Aristide's phase statement: the 9011 hardcode is a placeholder standing in for a table we do not have, and it should not be dressed up as a rule.
O9011 — ANSWERED, and it was the wrong worry
Jordan, 2026-08-04: "O9011, 9008, 9035, and more you'll see are pierce subprograms. Rule of thumb with Mitsubishi is any program starting with a 9 is their proprietary subprogram and they recommend that we only set these with the tables."
So this item spent a fortnight worried that every program we ship depends on a subprogram we have never read. We are not meant to read it. It is vendor firmware, selected from the condition tables, not authored by us. The worry was misplaced.
It leaves a real question in its place, which is a better one: there is more than one pierce subprogram — 9011, 9008, 9035 and others — and our post hardcodes pierce_sub=9011 (emit.py:1112). Which one a job should call for a given material and thickness comes from the tables. Asked 2026-08-04.
And the machine is a Mitsubishi, recorded here for the first time. The 9-series rule is a vendor convention, not a general one, so it travels with the make.
What the census inferred about O9011, and how it held up
Before Jordan answered, the census argued from the ON/OFF asymmetry — beam off 90 times and never on, height control off 91 times and never on — that O9011 must be switching those on. Jordan's answer neither confirms nor denies it: a pierce subprogram turning the beam on is exactly what you would expect, but nobody has read the file and, per the vendor, nobody is going to. The inference stands as an inference and is now unfalsifiable from our side. Recorded so it is never promoted to a fact.
What the glossary tells us that nobody asked
- Cutting conditions run to 16, not 13. M101–M113 select sets 1 to 13, then it jumps: M714/M715/M716 select 14, 15 and 16. Anyone extrapolating the pattern would have guessed M114.
- Do NOT assume M1xx and #1xx are the same table. The control has "cond data N select" M-codes and the programs carry condition variables #102–#111. They are numerically adjacent and it is tempting to link them, but the master sets ten variables while selecting only condition set 1. The glossary says nothing about the relationship. Open question, flagged here so it is not quietly assumed.
- The machine has G51 scaling, G51.1 mirror image, G68 coordinate rotate and G253 auto sheet position. When nesting arrives, part rotation and mirroring can be modal commands rather than baked coordinates. Not a decision, a note for item 3.
- M124/M125 corner control and M140/M141 spatter-preventing spray exist and neither shop file uses them. Worth asking Jordan whether that is a choice or a machine that does not have the option.
What is still waiting on the shop from this item: the contents of O9011, and the one-line confirmation on M121.
Both changes made — 2026-08-04
Jordan gave the go and issued a corrected program with the changes already in it (incoming/1785874049_2669550_65733.NC). Ours now matches it: M101 count 0, 90 M87 + 1 M121 with the M121 on the last boundary, 91 M199, 91 M98. A third change came with it that nobody asked for: pierce_clear.parse_nc located the pierce by testing for M101, so the moment M101 left the dialect it found zero boundaries and every caller — risk, tipping, the slug report — silently read an empty program. It now finds the first G0 in the block carrying both X and Y, which reads both dialects. Control: risk.analyse on the old master still returns exactly 4 / 2.8 / 0.8 / 300.2 and on the 07-29 file 33 / 955.9 / 228.2 / 1587.5, the recorded values, so the parser change moved nothing.