Table of Contents

Editing Contract

Every leaf of the Controller branch edits a different table, and almost all of them edit it the same way. This page is that shared way: what a leaf panel fetches, when an edit commits, what a failed write does, what a panel shows while its table is absent, and what it never notices. It owns no Control-Tree node of its own — it holds over every panel of the Controller branch on /equipment: the root at equipment/controller, and every leaf beneath equipment/controller/machine and equipment/controller/program-data. Each leaf page can then state only what is its own. The last section is the other half of the contract: every panel that departs from it.

Important

Anatomy makes no claim that these ids are stable across versions. See Tree Ids and Routes for the migration hop that keeps an older link resolving.

The Shape of a Leaf Panel

Each leaf panel takes one prop, the tree node, and reads the shared runner snapshot through a module-singleton composable whose installer it calls synchronously while its script runs rather than on mount. The installer is idempotent, so whichever panel mounts first pays for it and the rest get the cache. Only five panels read the node prop at all: three use its id to tell apart the sibling leaves they serve, and two use it as the scope of the structural change they report. One of the three serves every leaf of a group: Parameters (Native) is a Group stem whose three leaves — System Parameters, Axis Parameters and Axis Parameters (Integer) — share one panel, and that shared panel is what Parameters (Native) names on the rest of this page.

Beyond that shared snapshot, a panel owns its own table. It imports its reader and its setters directly from the branch's typed API module and fetches once, in onMounted. There is no store, no request queue and no batch: one panel, one read, one table. The two panels that fetch nothing — the branch root and Controller Brand — are exactly the two that have no table of their own and render off the snapshot alone. How the branch itself is built, rebuilt and selected belongs to the Control-Tree engine and is described in Control Tree.

Only one panel is mounted at a time. The editor column's remount key is composed from the node id, the node key and the mission stamp; controller nodes carry an empty key and no mission record, so the key reduces to the node id alone. Moving the selection therefore remounts and refetches; re-clicking the row already selected does neither.

When an Edit Commits

The commit rule is per control kind, and every panel that uses a given kind uses it the same way.

Numeric fields are the shared numeric widget, and it commits on blur or on Enter and on nothing else — never per keystroke. Its full contract, including what a bound violation does to the box, is Numeric Input. Two consequences matter here. Both paths end in the same equality guard: a commit whose value equals the one the field was given — compared as numbers, and again as the text the field shows, so rounding noise does not count as an edit — emits nothing. So leaving a field that was focused and not changed sends no request, and leaving it after an Enter does not send the value a second time. And the two halves of the rule are not wired alike: blur is the input component's own event and is raised only while the field is editable, whereas Enter is a plain listener on the underlying element and still fires on a read-only one — where the guard is what keeps it from writing, because a read-only field's value cannot differ from the one it was given.

Checkboxes, toggles and selects commit immediately, on the click or the pick. That covers the Stroke limit check toggle on Machine Limits (Stroke), the block-skip layer boxes, the tool-change Stays put box, the M-code tool-change box and its Spindle and Coolant selects, the tool-word trigger toggle, the cutter-compensation and tool-axis selects, and the tool-offset Set ideal offset dependent on tool house toggle.

Plain text fields have no shared widget and are wired twice over. The M-code Not-simulated note commits on the field's own change event, which carries the string and fires on Enter or on leaving a changed field. The two subprogram folder inputs bind blur and Enter explicitly, and commit as a pair.

Row actions — the datum reset-to-zero button, the work-coordinate P0 and M0 buttons, a delete button, an add button — commit on the click, and are not optimistic: they write first and touch the local rows only after the request resolves.

Two panels do not commit per control at all; they stage a draft behind an explicit button, and both are named below.

The Optimistic Write

A per-control commit follows one fixed shape. The handler captures the current value, assigns the new one so the screen updates at once, awaits the setter, and on failure restores the captured value and raises a toast. Nothing is queued and nothing is retried.

Two details of that shape are easy to misread from the screen:

  • The write is row-scoped even though the handler is per cell. Editing one cell of a work coordinate, a datum row, a frame or a tool-offset row sends the whole row or the whole XYZ triad as it stands after the edit. An M-code edit likewise sends all four declaration fields, which is why the wire format is a whole-declaration replace rather than a patch.
  • The rollback restores what the handler captured, which is usually narrower than what it sent. A work-coordinate, datum, frame or tool-offset handler captures the one cell it edited and puts back only that, though the request carried the whole row. Three handlers capture the whole set they send and restore it intact — the M-code declaration row, the tool-change Stays put pair, and the two subprogram folders. Either way, a failure the server had partly applied leaves the two sides disagreeing; the panel's recovery is the toast and a later remount, not a re-read.

Adds and removes are outside this shape, and the local rows never move before the request resolves. Two panels then append the returned row themselves — the generic tool-offset table and the Siemens $TC_DP table, the two whose add hands back a freshly minted key. The other five re-read their whole table instead: M-Code Declarations, Tool Names, R Parameters, Retained Common Variables and Parameters (Native). A delete usually filters the row out in place; Parameters (Native) re-reads there too. Three deletions are guarded by a confirmation dialog first: a tool-offset row, a Siemens $TC_DP row, and a native parameter. M-code declarations, tool names, R parameters and retained common variables delete on the click with no confirmation.

When a Write Fails

The branch's REST surface answers a missing dependency inside a success envelope rather than with an error status: the dependency lookup returns HTTP 200 carrying success: false and a message naming the type it could not find, such as No IStrokeLimitConfig on the active runner, and an exception raised inside the same lookup is reported the same way. The shared fetch helper turns both a non-2xx status and a success: false body into a thrown error, so a panel cannot tell the two apart; the first arrives with the status prefixed to the message, the second as the server's own sentence.

What the user sees is one negative toast, three seconds, composed as the panel's localized context followed by the raw server message — the locale bundle stores each error key as the bare context and the code appends the separator and the message. A failed write leaves no inline error state, no retry affordance and no dirty marker: once the toast expires, nothing on screen records that it happened. (The unsaved badge and the staged-brand banner on the two draft panels mark a pending edit, not a failed one.) A console error accompanies the toast.

The server message is not localized. Only a coded error payload can be re-rendered in the app locale, and the envelope this branch answers with carries no code, so its English sentence is appended verbatim under any language. The two writes that replace the whole runner answer with real status codes instead of the envelope: installing one through Object Management, and switching brand. Of the codes they raise, only not found with no project loaded carries the coded payload — the conflict raised rather than swapping the parser under an NC program that is playing or paused, and the refusals of an unknown key or an unknown brand, are all bare English sentences. One further status code sits on the datum routes, a defensive 400 for a table segment that is neither preset nor shift; the panel sends only those two, so nothing reachable from the branch produces it.

The Two Empty Layers

A leaf panel opens with two guards, in this order.

Layer one is the shared snapshot. The shared empty state renders the single line "No NC runner — load a project first." whenever the snapshot reports no runner. Every leaf panel carries it; the branch root is the one panel that does not, because it renders a richer block of its own.

Reaching that line by navigating is not possible: a leaf node is created only when the snapshot already reported a runner, and a deep link naming an id the built tree lacks is refused. The guard is live rather than navigational — it answers the snapshot emptying under a panel that is already mounted, which is what closing the project does.

Layer two is the panel's own read. Where the runner resolves but its table does not, the panel renders one line naming the absent table — "No block-skip config on the active runner.", "No Siemens frame table on the active runner.", "No tool-offset table on the active runner.", and so on, one string per table. Three panels key that line on one table: Controller Parameters, M-Code Declarations and Parameters (Native) all gate on the brand's controller parameter table and all render "No controller parameter table on the active runner." Controller Parameters is the loosest fit — its two iteration-guard fields resolve through dependencies of their own, and only its presence flag is the parameter table.

Controller Brand, which reads no table, has no second layer at all; every other leaf has one. Only after both guards does the editor body render. One panel keys its second layer on something other than its read's presence flag, and it is named below.

What a Mounted Panel Does Not See

The shared snapshot is fetched once per load of the application. The installer's flag lives at module scope, so a later call does nothing and only a browser reload starts over, and the snapshot is re-read on exactly three events afterwards: the project store's has-a-project flag turning true, an Object-Management install of a runner, and a brand switch. The flag turning false re-reads nothing — it clears the snapshot in place. No panel re-reads it either; the composable exposes a reload function that nothing in the branch calls.

Three consequences follow, and they are the contract's sharpest edges.

  • A project-to-project load does not refresh it. The has-a-project flag is derived from the project path being non-empty, and loading another project assigns the new path directly, so the flag never leaves true and the watch never fires. The page itself is destroyed and rebuilt, because the layout keys its keep-alive on a project epoch — but the rebuilt panels call the same now-idempotent installer, which does nothing. Meanwhile the branch builder makes its own, independent request for the same snapshot, so the tree shape can be built from the new project while every leaf gates on the old one.
  • Nothing pushes changes at a mounted panel. No panel holds a watcher, a poll or a status-hub subscription over its table. A write made by another browser tab, by an NC run, or by the server's own sweep after a brand switch is invisible until the panel is remounted by moving the selection away and back. Leaving the page and returning does not do it, because the page is kept alive and its panel with it. The one control that reads again on its own is the Stroke limit check toggle, each time the Equipment page is shown again — its departure is named below.
  • A panel's own edits do not update the snapshot or the branch. Deleting the last row of a table leaves both the cached snapshot and the tree branch as they were until one of the three refresh events happens.

Because the shared snapshot is a reactive reference, a panel does track it live once it changes — but with one panel mounted at a time, the change that matters in practice is a project close.

The Table Primitive

Where a leaf renders a table it is Quasar's markup table — dense, flat, bordered — with a hand-written header and body and a repeat over the rows. No panel in the branch uses the data-table component, and nothing else in the application does either. The practical difference is that these tables have no built-in sort, no pagination and no column menu: what the header says is what the column is.

Key columns are rendered as plain text and cannot be edited: the tool and edge numbers of a $TC_DP row, a tool name, an R number, a # variable number, a datum row index, a native parameter id, and the axis names of every per-axis table, which follow the machining chain rather than the panel. The one renameable key is the generic tool-offset row's tool number, and it is guarded against duplicates on both sides of the wire.

A table that can grow carries an add control, and the branch spells it three ways. Five carry a true footer below the table — the new row's fields, then a primary button: Add / Set on Tool Names, R Parameters, Retained Common Variables and Parameters (Native), Declare on M-Code Declarations. Two carry a fieldless button in the toolbar above the table instead, because the server mints the key: Add on Tool Offsets and Add Tool on the Siemens $TC_DP table. The last is Add Position on Indexing Position Tables, which appends an empty row to the local draft and sends nothing. Two tables carry a Show all toggle that hides an all-zero extended tail, on Work Coordinates and on Frames.

Nothing Guards a Switch Away

No panel in the branch registers the Control-Tree host's before-switch gate, and none exposes anything to the host at all. Selecting another node therefore always succeeds immediately. For the per-control panels that is exactly right — every edit is already on the server. For the two draft panels it means an unsaved draft and a staged brand are discarded silently when the selection moves, with no prompt and no warning.

Where the Wave Is Not Uniform

Everything above is the rule. What follows is every place the branch departs from it, panel by panel. A contract page without this section invites the next editor to tidy it into a uniformity that was never true.

Machine Limits / Rapid Feedrates / Home Reference — the presence flag is discarded

The axis-table panel serves three leaves and is the one panel whose second empty layer is not its read's presence flag: it keys on the row count instead. The rows and the flag are independent on the server, which builds one row per chain axis whether or not the backing config resolves and reports presence separately. So a runner with axes but no stroke-limit, rapid-feedrate or home config still renders a full, editable table, and every commit fails with a toast naming the missing dependency. What fills the cells differs by leaf: the stroke-limit and home values are nullable and come through blank, while a rapid rate is a plain number the server defaults to 0, so that one leaf shows a table of zeros that never signals the absence at all.

Machine Limits (Stroke) — a project switch with its own reads, lock and failure state

The Stroke limit check toggle on Machine Limits (Stroke) is a project setting rather than a row of the runner's tables, and it departs from the rule on five counts.

  • A second read, outside the branch's surface. The toggle reads and writes the switch on /api/Controller, through that surface's own client rather than the branch's typed API module, so the limits leaf fetches twice on mount — its rows and the switch — where every other leaf fetches once. Both calls take the plain-JSON helper rather than the envelope helper. The two routes answer real status codes instead of the envelope — 404 with the coded no-project payload, which the helper re-renders in the app locale, or 500 with a bare message — so the plain-JSON helper misses nothing there.
  • Re-read each time the page is shown again. The Equipment page is kept alive while another page is open, so returning to it remounts nothing, and every other read on the branch — the rows beside the toggle included — stands as it was when its leaf mounted. The toggle reads its value again each time the page is shown, not only when the leaf mounts, skipping that read while its own write is in flight, so a value changed meanwhile by a mission script, through SessionShell.EnableStrokeLimitCheck, or over REST is on screen when the user comes back.
  • Disabled until a read answers. The toggle is drawn at once, above the rows and the no-axes line alike, and cannot be clicked before its value has arrived.
  • Disabled while its own write is in flight. From the click until the write answers, the toggle holds still, so a second click cannot overtake the first. No other per-control commit on the branch locks itself this way; the nearest is Controller Brand, whose Apply brand and Revert are disabled while its apply is out.
  • A failed read can leave it disabled. The failure raises a toast headed Load stroke limit check. Before any read has answered, the toggle stays disabled until one does — on a remount, or when the Equipment page is shown again — while the rows beside it render as usual; the panel's own row read, by contrast, leaves the no-axes line behind when it fails. A failed write follows the ordinary shape: the toggle flips back under a toast headed Save stroke limit check.

Controller Brand — staged, confirmed, and destructive by design

Controller Brand is one of two panels with no table read of its own, the only panel with no local error handler, and one of the two whose write replaces the whole runner — the branch root's Object-Management install is the other. The select stages a pending brand rather than applying it; Revert drops the staging, an orange banner spells out what the switch destroys, and Apply brand opens a confirmation dialog before the request. Its failures surface through the shared composable's global notification rather than the panel's own, so the console line names the shared state and not the panel.

Controller root — its own empty block, its own toast

The branch root panel does not use the shared empty state. It renders an hourglass over its own no-runner title and hint. Its error path also differs: it takes an already-composed string from the Object-Management button, omits the console line, and uses a longer toast than every other panel.

Indexing Position Tables — draft, validate, save whole

The one draft table. Its numeric cells bind straight into a local draft row with no handler, an unsaved badge appears while the draft differs from what was saved, and nothing reaches the server until the per-table Save Table button, which stays disabled while the draft fails validation. The validation mirrors the endpoint's own rules — a per-table maximum, strictly ascending values, and a 0 ≤ position < 360 range when a modular rotary axis reads the table — and reports the first violation under the table. A failed save deliberately does not roll the draft back: the draft stays dirty so the edit is not lost, which is the opposite of every other panel.

Its axis-assignment table above the drafts is display-only. The assignment is not editable on this panel and the endpoint exposes no writer for it; the value is edited as a per-axis integer parameter in Parameters (Native), which is what the panel's own hint says — on that group's Axis Parameters (Integer) leaf.

Subprogram Folders — two fields, one write

The two folder inputs are plain text fields committed together on blur or Enter of either one, and the guard against a redundant write is a saved snapshot of both values rather than a per-field captured value. Editing one folder writes both.

M-Code Declarations — a third text-commit wiring, and an add that submits on Enter

The note cell is the only text cell in the branch that commits through its field's native change event rather than an explicit blur binding or the numeric widget. The timing matches; the wiring is a third variant. This is also the only add-row footer whose input submits on Enter.

R Parameters and Retained Common Variables — the two panels that commit a null

Every other numeric handler returns early on a null and treats a cleared cell as no edit. These two send the null, because an empty value is a real state in both tables — the vacant entry, which a program reading it reports as an error rather than silently taking as zero.

Tool Offsets — read-only ideal columns, and a two-call rollback

With the tool-house dependence on, the two ideal columns are made read-only rather than hidden. A read-only field is still focusable, and the widget's Enter binding is a plain listener on the underlying element rather than the component event blur travels on, so Enter in one of those cells does reach the commit — and stops at the widget's equality guard, because the value in a read-only cell is the one it was given; focusing it and leaving does not even get that far, because a non-editable field raises no blur. Neither path writes. The tool number column, by contrast, is swapped for plain text and is genuinely inert. The tool-change position field takes a third route — it is disabled rather than read-only while its axis stays put, and a disabled field takes no keystrokes either.

Turning the dependence on also makes two server calls inside one try: the toggle write, then the refresh from the tool house. If the second fails after the first succeeded — the refresh answers unsuccessfully when the project carries no tool house — the catch reverts the local toggle while the server has already committed it.

Work Coordinates — a row click that writes outside the branch

Clicking a row picks which coordinate the Equipment canvas marks, and that write goes to the equipment-display surface rather than to this branch's own. Like the two Stroke limit check calls above, it goes through the plain-JSON helper instead of the envelope helper, so only a transport failure throws there. The row click is bound on the whole row with no click-stopping on the cells or the P0 and M0 buttons, so acting anywhere in a row marks it; a same-id short circuit is what keeps cell editing on the marked row from writing again on every pass through.

Two truth sources for “this is Siemens”

The tree relabels the generic Tool Offsets leaf from the snapshot's $TC_DP flag, while the tool offsets panel shows its ISO-G43-H caveat, and the controller parameters panel picks its macro-guard labels, from the brand string instead. The brand marker is a free-form string that can be edited independently of the dependency list, so the label and the caveat can disagree.

The error handler does not agree with itself

Every panel that has a local handler composes the same toast through one signature carrying two incompatible conventions. Nine pass a localization key and translate inside the handler; eight pass an already-translated string. Both first parameters are typed as a plain string, so nothing separates the two conventions at compile time. Nothing user-visible changes; the console line does — the key-style panels log the raw key path, the string-style panels log the rendered sentence.

The add-row footers disagree on two details

Whether Enter submits: only M-Code Declarations binds it. Whether the fields clear after a successful add: M-Code Declarations clears its code, Tool Names clears both fields, and R Parameters, Retained Common Variables and Parameters (Native) leave what was typed in place.

A source comment the code contradicts

The shared composable's header names the Execution page as the owner of the Controller root. The root is built by the equipment-scoped host, which only the Equipment page creates, so the code is what ships. The shared empty state's comment reads like a second case and is not one: the number in it counts the byte-identical copies its extraction removed, not the call sites it has today, which are one more.

Layout

  • Editor Column — beside the Control Tree column of /equipment, at the page's full height: the panel of whichever controller leaf is selected, one at a time
    • No-Runner Body — "No NC runner — load a project first."; shown first, from the shared snapshot
    • Stroke limit check Toggle — Machine Limits (Stroke) only: under the no-runner check and above everything else on the leaf, the no-axes line included, with its scope caption beneath; disabled until a read answers and while its write is on its way, and re-read each time the Equipment page is shown again
    • Absent-Table Body — one line naming the table this leaf edits, from the panel's own read
    • Editor Body
      • Description Caption — the leaf's own one-line explanation, above the table
      • Toolbar — where the add button carries no fields: Add on Tool Offsets, Add Tool on the Siemens $TC_DP table, beside that panel's own toggles
      • Table — dense, flat, bordered, no sort and no pagination
        • Header Row — the leaf's own columns, over the shared labels Axis, Id, Value, Unit and Actions
        • Data Row — a bold plain-text key cell, then one editable cell per column, then the row's action buttons
      • Add Row Footer — the new row's fields, then Add / Set or Declare
      • Show all Toggle — Work Coordinates and Frames only, revealing the all-zero extended tail
      • Draft Bar — Add Position, Revert and Save Table with an unsaved badge on Indexing Position Tables; Revert with Apply brand on Controller Brand
  • Toast — negative, three seconds, the panel's context followed by the server's own message

Source Code Path

See HiNC App Anatomy for git repository links.

Web Application

HiNC-2025-webservice (Quasar CLI SPA):

  • wwwroot-src/src/composables/useSoftNcRunner.ts — the shared snapshot every panel gates on: the module-scope installed flag, the project-presence watch, the three events that re-read it, the reload no panel calls, and the global notification the brand panel's failures take.
  • wwwroot-src/src/api/softNcRunner.ts — the branch's typed REST wrappers: the snapshot parser, one reader and one setter family per table, and the whole-row payloads the per-cell handlers send.
  • wwwroot-src/src/api/http.ts — the two failure shapes a panel cannot tell apart, and the coded error rendering that a message without a code falls through.
  • wwwroot-src/src/components/widgets/NumericInput.vue — the numeric field: commit on blur or Enter, no per-keystroke emit, the equality guard both paths end in, and the Enter listener that keeps firing where a read-only field's blur is suppressed.
  • wwwroot-src/src/components/controlTree/SoftNcEmptyState.vue — the shared no-runner line, and the comment that counts the copies its extraction removed rather than its call sites.
  • wwwroot-src/src/components/controlTree/softNcItemTypes.ts — the branch builder: the node ids the three multi-leaf panels discriminate on, and the empty node key that reduces the remount key to the id.
  • wwwroot-src/src/components/controlTree/PrimarySlavePanel.vue — the editor column: the remount key, the one-panel-at-a-time mounting, and the events it wires to the host.
  • wwwroot-src/src/pages/EquipmentPage.vue — the page that sets that editor column beside the tree column at the page's full height.
  • wwwroot-src/src/components/controlTree/useControlTreeHost.ts — the before-switch gate no panel in this branch registers, and the rebuild that a reported structural change triggers.
  • wwwroot-src/src/components/controlTree/SoftNcAxisTablePanel.vue — the three per-axis leaves, the second empty layer keyed on the row count instead of the presence flag, and, on the limits leaf, the Stroke limit check toggle with its second read, its re-read each time the kept-alive page is shown again, its in-flight lock and the disabled state a failed first read leaves.
  • wwwroot-src/src/api/controller.ts — the toggle's client, outside the branch's typed module: the read and the write of the switch through the plain-JSON helper, which throw on a 404 or a 500.
  • wwwroot-src/src/components/controlTree/SoftNcBrandPanel.vue — the staged select, the revert, the confirmation and the structural change it reports.
  • wwwroot-src/src/components/controlTree/SoftNcRunnerRootPanel.vue — the panel with its own empty block and its own toast shape.
  • wwwroot-src/src/components/controlTree/SoftNcIndexingPositionsPanel.vue — the draft table: the unsaved badge, the client-side mirror of the endpoint's rules, the save that keeps a failed draft, and the display-only assignment column.
  • wwwroot-src/src/components/controlTree/SoftNcSubprogramPanel.vue — the two text fields committed as a pair against a saved snapshot.
  • wwwroot-src/src/components/controlTree/SoftNcMCodesPanel.vue — the change-event text cell, the whole-declaration write, and the only add input that submits on Enter.
  • wwwroot-src/src/components/controlTree/SoftNcToolOffsetsPanel.vue — the read-only ideal columns whose Enter reaches the guard and stops there, the renameable key with its duplicate guard, and the two-call dependence toggle.
  • wwwroot-src/src/components/controlTree/SoftNcWorkCoordinatesPanel.vue — the row click that writes to the display surface, and the row-scoped triad write.
  • wwwroot-src/src/components/controlTree/SoftNcRParametersPanel.vue and wwwroot-src/src/components/controlTree/SoftNcRetainedVariablesPanel.vue — the two panels that commit a null to vacate an entry.
  • wwwroot-src/src/components/controlTree/SoftNcSiemensToolOffsetsPanel.vue and wwwroot-src/src/components/controlTree/SoftNcNativeParamsPanel.vue — the other two confirmed deletions, and the two add flows that part company: one appends the minted row, the other re-reads the whole table.
  • wwwroot-src/src/components/controlTree/SoftNcToolNamesPanel.vue, wwwroot-src/src/components/controlTree/SoftNcToolChangePanel.vue, wwwroot-src/src/components/controlTree/SoftNcDatumTablePanel.vue and wwwroot-src/src/components/controlTree/SoftNcControllerParamsPanel.vue — the conforming shape: one read on mount, per-control commit, capture-assign-await-restore, one toast. The tool-change Stays put box is the one handler among them that captures and restores a pair of fields.
  • wwwroot-src/src/api/equipmentSetup.ts — the canvas marker id the work-coordinate row click writes, outside this branch's own surface and through the plain-JSON helper.
  • wwwroot-src/src/stores/project.ts — the has-a-project flag the shared snapshot watches, and the direct path assignment that keeps it true across a project-to-project load.
  • wwwroot-src/src/layouts/MainLayout.vue — the keep-alive that keeps a page, and the panel in it, mounted while another page is open, and the project epoch that rebuilds the page without re-running the idempotent installer.
  • wwwroot-src/src/i18n/en/softNc.ts — every empty line, column header, hint and error context this branch renders, and the convention that an error key stores the bare context.
  • wwwroot-src/src/i18n/en/common.ts — the shared column and action labels the tables reuse.
  • Mech/SoftNcRunnerController.cs — the REST surface: the dependency lookup that answers a missing table inside a success envelope, the reads that report presence independently of their rows, the rapid rate defaulted to zero where its config is absent, the two runner-replacing writes that answer real status codes instead, and the datum routes' defensive rejection of an unknown table segment.
  • Controller/ControllerController.cs — the toggle's two routes, which answer real status codes rather than the envelope: 404 with the coded no-project payload, 500 with a bare message.
  • Common/ApiError.cs — the coded payloads, and why only the no-project answer can be re-rendered in the app locale.

See Also

  • Controller Branch — the branch these rules hold across, its two planes and the runner behind them
  • Machine and Controller Plane — the plane whose seven leaf pages this contract lets stay short
  • Program Data Plane — the other plane these rules hold across, whose six leaf pages inherit them the same way
  • Brand Matrix — which leaf exists on which brand, and the snapshot flags the first empty layer reads
  • Numeric Input — the numeric field's own contract: what parses, what the bounds do, and why Enter commits twice
  • Controller Brand — the staged, confirmed, whole-runner write that departs furthest from these rules
  • Per-Axis Tables — the three leaves whose empty layer keys on the row count, the Stroke limit check switch on the first of them, and the tool-change position beside them
  • Interface Parameters — the interface parameter form and the canned-cycle field, both plain per-control commits
  • M-Code Declarations — the whole-declaration write and the change-event text cell
  • Program Reading — the block-skip boxes and the paired folder inputs
  • Indexing Position Tables — the draft-then-save table, the one panel that keeps a failed edit
  • Native Parameters — the confirmed deletions and the add-or-set footer that keeps what was typed