Table of Contents

Program Branch

Program is the second of the four roots of the Execution page's Control Tree, Mission above it and Step Variables Branch and Step Colors Branch below: route /execution, Control-Tree path execution/program, one node per NC source file the session read. It is a read-only view of a run — the file's text, the passes that went over it, the per-line marks the run left behind, and the writeback files the run wrote — assembled from session data rather than from anything typed into it. Its node ids are positional, so an id addresses a node without surviving the branch growing around it.

Program Against Mission

Mission is what a run executes; Program is what the run read. That one difference sets the rest of the branch:

  • Mission's nodes edit the project. Program's item types declare a panel — and, on the root and the file node, a child builder — and nothing else: no enable checkbox (the tree hides the tick on every node that is not a Mission command or an enable-bearing Mission section), none of the row affordances a Mission row carries (no drag handle, no add, delete, move or duplicate button), and no counterpart to Mission's one panel-side structural edit, the multi-pick insert of the Program File editor.
  • Mission's shape is authored. Program's shape is a consequence: a subprogram file appears on it only because a run followed a call into it.
  • Mission belongs to the project. Program's contents belong to the session — the index behind it is fed piece by piece as the run executes, and it is dropped when the session ends or the project changes.

Before anything runs the branch is not empty. The server seeds it by walking the mission root-first through its nested lists — skipping a disabled entry along with everything beneath it — and taking the NC file of every Program File command and the title of every NC Code command. It seeds one placeholder per distinct string, not one per command: both loops append only where no root already carries that string under the same case-insensitive, slash-normalised comparison the sibling merge uses, and they share one namespace, so a Program File path and an NC Code title that normalise alike collapse into one node. A Program File command whose path is still unset is skipped and seeds nothing. A placeholder carries no invocations, so its panel shows the file's text with no marks and an empty, disabled pass selector.

The branch carries no transport of its own either. The Execution Tool Bar sits in the Control Tree pane's run header — above the tree scroller, beside the execution-status badge, on the Execution page only — so a run can be started, stepped and reset while a program file is on screen, and the editor pane below the tree shows nothing but the selected node's panel.

The Nodes the Branch Mints

Four item types. Three are keyed by position rather than by identity; the fourth, the run's result node, carries a fixed id.

The branch root (execution/program) carries the summary panel and the child builder that fetches everything.

A file node is one source file as reached through one call edge. The server groups executed sentences by the file index stamped on them, resolves each invocation's caller from the call-stack record on the executed piece, and nests the callee's node under the caller's; the same subprogram called from two different files therefore appears once under each. Sibling nodes merge on a case-insensitive, slash-normalised path comparison, so repeated passes over one file under one caller collapse into a single node holding several invocations. Placeholders are appended after the nodes a run produced, and one whose path a run node already holds is skipped rather than doubled — that skip is also what keeps an inline command to one node, because the run stamps the command's title as the path of every piece it plays, so the placeholder and the run node carry the same string. A later pass flags every root whose path matches an enabled NC Code command's title as inline; that flag drives three presentational choices — the label prefix, the panel's inline caption and which missing-text wording it shows — and one behavioural one: the root's child builder matches a node against the writeback conversions only when the node is not inline, so an inline root is never stamped with a conversion, never gains the forward links to a converted file, and cannot be the target a conversion's converted from header jumps back to. The tree label is the path's base name, prefixed (inline) for an inline node and suffixed with a multiplication sign and a count when the node holds more than one invocation.

A conversion node is one NC writeback conversion held by the session, labelled with an arrow and the written file's base name. Conversion nodes are appended after all file nodes.

A geometry-difference result node is this run's ideal-versus-machined comparison, at the fixed id execution/program/geom-diff and labelled Geometry Difference [<detection radius> mm] — the radius the overlay was built with, trimmed to three decimals, or an em dash when the server reports none. It exists only while a computed diff overlay is attached to the live meshed tree, it is appended last, after the conversion nodes, and it is the only node on this branch whose panel writes anything: the colour-scale radius the overlay is read with. The comparison itself is never started here — it comes from the mission's Post-Execution command, in its Geometry Difference Detection section, or from a script's Diff(r).

A file node's id is its parent's id plus its index among that parent's children (execution/program/0, execution/program/0/1); a conversion node's is the branch root's id plus dst- and the conversion's position in the session's list. Both are positional, and the tree those indices count into grows as a run discovers files, so a ?tree= link into this branch names a position and not a file. The result node is the exception: its id is the branch root's plus the literal geom-diff, so that one link addresses the same thing across rebuilds — on the runs that have one at all.

The whole branch costs three requests, made in that order: GET api/NcProgram/files, GET conversions, then GET /api/Workpiece/diff-settings. The root's child builder takes the file tree in the first response and the conversion list in the second, stashes each file's raw subtree on the node it mints, and the file nodes' builder only maps what is already there — no node fetches for itself; the third says whether a diff overlay is attached and with which detection radius. Each later request is an optional overlay on the one before it: a failed file-tree request yields an empty branch rather than an error, a failed conversion request leaves the file tree standing without cross-links, and a failed diff-settings request costs only the result node.

Invocations

An invocation is one pass over one file, keyed on the file index the run stamps onto every executed sentence. A fresh index is allocated for each top-level play of a file and for every subprogram call, call repetition and loop or jump re-segmentation, so a file entered or looped over more than once contributes one invocation per pass, and the file panel's pass selector is exactly a pick among them. Each entry reads as a hash-prefixed ordinal and a trigger, and the trigger is derived from the piece that opened the pass:

  • the call term with its P word — M98 P8, M198 P8 — when the piece carries a Fanuc subprogram-call record. Only that record is read, so a pass opened by a Siemens or Heidenhain call, or by a Fanuc macro call, falls through to the two cases below;
  • re-entry when this session has already seen a pass over the same path;
  • top otherwise.

The selector opens on the last invocation in the node's list — the pass that started most recently — and re-defaults whenever a rebuild leaves the current selection absent from the list. It is disabled while the node has none, and it takes typed text as a filter over the entries. Everything below it belongs to the selected pass alone: switching passes drops the mark and link caches and refetches both for every page of text already loaded, not only for the pages on screen. The footer counts the file's lines and, for the selected pass, the number of distinct source lines that executed in it.

What a Run Marks

The line viewer is virtualized. Text arrives in 1000-line pages covering the visible window plus two pages either side; the server caps one request at 2000 lines and keeps a small most-recently-used cache of whole files keyed on path and last-write time, so paging through a long program does not re-read it once per page. A path with no file on disk is answered as non-existent, the miss is cached so scrolling does not re-fire it, and the panel captions the file as missing — or, for an inline node, as inline text that is no longer available, because an NC Code command's text is served from the mission command itself and goes when the command is removed or retitled. A disk file wins over a command title that shadows it.

Marks are fetched the same way and per selected pass. A line the pass executed carries the sentence index it ran and the range of machining steps that sentence produced; a line absent from the answer did not execute in that pass and is greyed — but only once the node holds at least one invocation, so a placeholder's text renders plain rather than uniformly grey. A line whose sentence produced steps carries a step badge, single-valued or a range.

Marks grow as a run advances, so a page cached early would keep later lines looking unexecuted. The panel drops its mark cache and re-fetches the visible window on every throttled CL-strip update broadcast.

Clicking a line points the shared sentence cursor at that source position, which is what fills the Step Info column's Block Info panel; when the line's sentence produced steps, the click also selects that sentence's first step, moving the charts and the 3D strip with it. A line with no steps — a G54, a comment, a line that never ran — moves the cursor alone. Hovering a line sends the same anchor as the entered step on a 50 ms leading-edge throttle, and leaving the viewer clears it.

The traffic runs the other way too, on two paths. The broadcast path is shallow: any step selection, from any tab or from code, lands on the cursor, and the mounted file panel — only when its path matches — switches to that step's pass and reveals the line. The click path goes further. A step picked by a left click on a chart or on the tool path reaches the host's revealStepInProgram after the step is selected, and that call never selects a step: it switches Follow off and, when the selection is in the Program branch — the root or any node under it — resolves the step's file node, a subprogram node included, re-reading the branch once for a file or a pass the snapshot does not list yet, parks the jump and moves the selection there through requestSelect, a user act that writes ?tree=. When the step's node is the selection already, the mounted panel takes the jump through a watcher, so re-clicking the selected step scrolls the line back into view. A selection resting on Mission is not taken: that panel may hold staged edits. The reveal hangs on the click, not on the StepSelected broadcast — that reaches every tab, carries only the step index and is silent when the selected step is selected again; a 3D click is relayed by the server to the clicking canvas's connection alone (StepClicked on the rendering hub). A late answer is dropped: the reveal gives up when a user selection, the route or Follow moved while sentence-of-step was on its way. A target the panel's scroller cannot take — unsized, or hidden under a collapsed editor row — is parked and applied when the viewer regains height; the row is never expanded for it. Both paths mark the cursor's origin as a step, which is how Block Info tells a step whose play kept no block data from a line that did not run.

sentence-of-step says more than whether the step is there (with no strip it is a bare found: false). Without a step it carries stripCount, running and locked (a run is live, running or paused, so the pipeline may still fill a position), and notBuiltYet when the index is the next one a built step takes once a play began; for a built step whose sentence has no file line (a session script's act) it carries the step's sentenceIndex with found: false. A Collision--Detected is anchored to the index its pose's step takes and said before that step is built (so are the licence and lease refusals said before a step is granted and Player-Run--Fault; a Step-Task--Fault names a step whose building failed), so it can name an index no step holds yet, or, after a stop and a start without a reset, an index a later step took: the step is the message's only when the answer's sentenceIndex is the message's. The Session Message Panel reads its step rows' anchors that way, and so can a client polling GET api/Execution/messages (Replay Acceptance §5); the comparison holds within one numbering of the sentences. The other step messages are not compared: a script's, a tool change's, a line end's and an empty spindle's are anchored to the next built step by design, and a stroke-limit report, which names no sentence, to the step it checked, or to the next built step when the motion it checked built none.

Follow is the live variant. It lives on the Program row of the Control Tree, not in a panel, because it is cross-file: while it is on, the host moves the selection to the file node the execution-status hub's cursor is in — re-reading the branch for a file or a pass it has not listed yet — and the file panel switches to the executing pass, scrolls to the executing line and shows a read-only following badge. It is off by default and session-only, outside stored preferences, since a flag that survived a reload would seize the next run's selection. Any selection of the user's own switches it off — a tree node, a chart or tool-path click, a line click in the viewer — and while it drives, the selection moves without writing ?tree=.

Writeback Conversions

The session retains the destination piece streams and source-to-destination maps of its latest CL-to-NC writeback run — NcConversions(API), refilled by ConvertClToNcFiles(API). This branch only displays them; the writeback itself is switched on by the mission's Post-Execution command, in its CL → NC Writeback section. Because the conversions live on the session, they go when it does.

A conversion node shows the written file's lines, each line whose piece has a registered source carrying a back-arrow badge naming that source line. The panel's header names this conversion's source file; the link on that name lands on the file's node when a root file node matched the conversion's source path, and otherwise falls back to the first entry of the branch's file-index map, so a conversion whose source was reached only as a nested or inline node can name one file and open another. Clicking a badge selects the source node, switches it to the invocation the piece came from, and scrolls to the line; clicking anywhere else on a row only highlights it. The viewer has no missing-file caption of its own, so a written file no longer on disk renders as an empty viewer.

The reverse direction is carried by the file panel. A root file node whose path matches a conversion's source path gets forward-arrow badges naming the destination line, with a count when one source line produced several destination lines, and clicking one selects the conversion node and scrolls to the first of them. That matching is done on root nodes only, and never on an inline node, so a subprogram file reached through a call carries no forward badges of its own even though a backward jump can land on it and switch its pass.

The jump itself rides one shared slot, because only one editor panel is mounted at a time: the requesting panel parks the target line and emits a selection, and the twin takes the parked jump when it mounts — or through a watcher, when it was already the selected panel. The click-driven reveal above parks in the same slot, and a jump is dropped once the selection settles on any other node. A target consumed before the first page of text resolves is parked again and re-applied once the line array is sized.

When the Branch Is Rebuilt

  • Page initialization. Building the Execution page's four roots builds the branch, and only when a project is loaded; without one the root stands with no children.
  • Any change in the broadcast execution status, or a reset counted beside it. The status the hub reports is one of NoProject, Ready, Running, Paused and Finished, and the host watches executionStatus|resetCount — that status folded together with the service's reset counter — so it re-reads the branch whenever either moves. The counter is in the key because a reset broadcasts twice with the same status: the Finished → Ready flip first, the reset itself — run data and diff overlay gone — after, and on the status alone that second broadcast is swallowed and the result node outlives its result until the next Refresh. It deliberately does not take the structural-change path used elsewhere in the tree, because that path force-expands the node it rebuilds and a run would then keep re-opening a branch the reader had closed. The panels pick up part of the change from the replaced nodes: the path caption, the pass selector, the inline wording and the executed-line count are all derived from the node, but the file text is not — it is fetched once per page on mount and on scroll, with no watcher on the path, and the panel is not remounted because its key — the node id, the node key and the mission stamp — reduces on a Program node to the id alone, the other two parts being empty, and the id is positional and therefore unchanged. A rebuild that puts a different file at the same index leaves the previous file's text on screen under the new node's caption and marks.
  • The Refresh button on the Program row. This one does take the structural-change path: it re-reads the file tree from the current session and expands the branch. A difference computed outside a run — by a script, between two transitions — reaches the branch this way and no other. Both this path and the status watcher fall back to the branch root when the re-read drops the selected node, so a result node that has just gone never leaves the editor column pointing at nothing.

A reset is the emptying event: it ends the session, clears the index and retires the diff overlay with the meshed tree, so the next read of the branch returns the mission's placeholders and nothing else — no conversion nodes, no result node.

The Recompute Button

The Program row carries a second button beside Refresh, and it is the one mutating action anywhere on this read-only branch: Recompute re-derives the run's step physics in place from the stored cutter–workpiece engagement against the current flute offset and setup angles, cutter geometry and materials, workpiece material, cutting parameters, environment — ambient temperature and coolant condition — and spindle capability. It is allowed here because it changes nothing but the run's own results — the file-producing actions still live under Mission › Post-Execution. What the operation does and what each kind of change costs is Recomputing a Finished Strip.

  • It is physics-only chrome. The button is rendered only while the Show Physics Options preference is on, like the other physics-gated tree content.
  • It blocks for the whole computation. POST /api/SessionShell/RecomputeStepPhysics returns when the recompute has ended, so the button's spinner and the footer's in-flight zone span it. The footer shows the chunk progress the engine reports to the shell message sink, which is what distinguishes a recompute from a play mid-mission: the status badge reads Running either way.
  • Nothing else hangs on the response. The panels refresh from the clStrip hub's physicsRevision, and the status badge and the button's own enable state follow the engine — so a proxy that cuts a long response costs the result toast, not the refresh.
  • No dirty-switch gate. The material, cutting-parameter, cutter, ambient-temperature, coolant and spindle-capability editors commit per field, so there is no staged edit a recompute could miss.
  • Outside a session — nothing played since the last Reset — the mirror answers 409, surfaced as a play first warning rather than an error.
  • The result is surfaced from the run's own messages, with a cap on how many become toasts; the rest stay in the footer history.

Layout

  • Program Node
    • Intro Caption
    • Status Row
      • Run-State Badge — reads run data when any of the branch root's direct file children holds at least one invocation and not run yet otherwise; like the count beside it, it looks one level deep and never at nested subprogram nodes. It is computed from the nodes, not from the file-tree response's own run-data flag.
      • File Count Caption — the branch root's direct file children only; nested subprogram nodes are not counted.
      • Converted File Count Caption — shown only when the session holds conversions.
    • Not-Run Hint — shown while the badge reads not run yet.
    • Conversions Hint — shown only when the session holds conversions.
    • Geom-Diff Hint — shown only while the branch holds the geometry-difference result node.
  • Program File Node
    • Path Caption — the path as the run stamped it; an inline node appends an inline-NC-code tag.
    • Pass Select
    • Following Badge — read-only, shown while Follow is on and the run is in this file.
    • Not-Run Hint — shown while the node has no invocations.
    • Missing-Source Caption — the disk-file wording or the inline-text wording.
    • Line Viewer
      • Line Number
      • Line Text
      • Step Badge
      • Converted-Line Badge
    • Count Footer — line count, plus the selected pass's executed-line count.
  • Converted File Node
    • Path Caption
    • Converted-From Line — the source file's name, linked to its node when a root file node matched.
    • Line Viewer
      • Line Number
      • Line Text
      • Source-Line Badge
    • Count Footer — line count and converted-piece count.
  • Geometry Difference Node
    • Title Row
      • Diff / No diff Badge — the panel's own re-read of the server, not the label it was minted with.
      • Detection-Radius Badge — read-only, shown only when the server reports one; its tooltip says the visual radius is independent of it.
    • Caption
    • Visual Radius Number Field (mm)
    • Visual Radius Slider — spans (0, max(detection radius, last accepted visual radius)] in hundredths, so a value typed past the detection radius stays reachable by drag; the range is derived from the last value the server accepted, never from the value under the thumb.
    • Saved-With-The-Project Hint
    • Error Caption — the refusal of a value that is not finite and positive, or the no-workpiece note.

Source Code Path

See HiNC App Anatomy for git repository links.

Web Application

HiNC-2025-webservice (Quasar CLI SPA):

  • wwwroot-src/src/components/controlTree/programItemTypes.ts — the branch's four item types, the node ids, the labels, the conversion stamping, and the three-request child builder that appends the result node only when the diff settings report an attached overlay.
  • wwwroot-src/src/components/controlTree/ProgramRootPanel.vue — the branch root: intro, run-state badge, file and conversion counts, and the three hints — not run yet, conversions, and the geometry-difference one shown while the result node stands. It carries no buttons; Follow, Refresh and Recompute ride the Program row.
  • wwwroot-src/src/components/controlTree/ProgramFilePanel.vue — one source file: the pass selector, the following badge, the paged line viewer, the execution marks, the step and converted-line badges, the cursor and hover wiring, the incoming jump and the reveal gate.
  • wwwroot-src/src/components/controlTree/ProgramConversionFilePanel.vue — one written file: the paged line viewer and the source-line links back into the file panel.
  • wwwroot-src/src/components/controlTree/ProgramGeomDiffPanel.vue — the result node's panel: the Diff / No diff badge, the read-only detection badge, the visual-radius input and slider, and the re-read on mount and on every new node object a rebuild hands it.
  • wwwroot-src/src/components/controlTree/useControlTreeHost.ts — declares the branch root as the Execution page's second root, below Mission, re-reads it on every executionStatus|resetCount change without expanding it, serializes every re-read of the branch, carries the Program row's Refresh with its selection fallback, drives live follow and revealStepInProgram, and hides the tick on every node that is not a Mission command or an enable-bearing Mission section.
  • wwwroot-src/src/components/controlTree/itemTypes.ts — the node shape carrying the program bookkeeping, the merged item-type registry, and the eager subtree builder.
  • wwwroot-src/src/components/controlTree/ControlTreePanel.vue — the tree pane that renders the branch's nodes, binds the tree's strict tick strategy, and pins the run header — the transport bar and the execution-status badge — above the tree on the Execution page.
  • wwwroot-src/src/components/controlTree/PrimarySlavePanel.vue — mounts the selected node's panel under a key built from the node id, the node key and the mission stamp — the last two empty on every Program node — and forwards its selection request to the host.
  • wwwroot-src/src/api/ncProgram.ts — the typed client for the file tree, the paged lines, the line marks, the syntax piece, the sentence-to-step mapping and both directions of conversion links.
  • wwwroot-src/src/api/workpiece.ts — the typed client for GET / POST /api/Workpiece/diff-settings: the visual radius, the nullable detection radius and hasDiffOverlay.
  • wwwroot-src/src/api/clStrip.ts — the step-select and step-enter posts a line click and a line hover make.
  • wwwroot-src/src/composables/useProgramLineJump.ts — the single parked-jump slot the two viewers and the host's reveal hand a target through, and the reveal sequence every user selection bumps.
  • wwwroot-src/src/composables/useSentenceCursor.ts — the shared source position, written by a line click and by the resolved step selection, each marking its origin.
  • wwwroot-src/src/composables/useClStripHub.ts — the throttled run-advance counter that invalidates the visible marks.
  • wwwroot-src/src/composables/useExecutionStatusHub.ts — the status the branch rebuild watches and the running cursor Follow scrolls to.
  • wwwroot-src/src/components/execution/SyntaxPiecePanel.vue — the Step Info column's Block Info Panel, the other reader of the shared cursor.
  • wwwroot-src/src/i18n/en/tree.ts — the branch's labels, hints, badges and pluralised counts.
  • Execution/NcProgramController.cs — the read-only endpoints: the file tree, the paged file lines with their inline-command fallback and whole-file cache, the line marks, the syntax piece, the sentence and step lookups, the conversion list and both directions of conversion links. What the syntax piece carries for Block Info is on Block Info Panel.
  • Execution/NcProgramRegistryService.cs — the session-scoped index: the event feed, the invocation records with their trigger and caller resolution, the file-tree snapshot with its mission placeholders, the per-line marks, what Block Info reads — the run order, the call lines and each pass's place among its tree node's — and the clears: on reset, on project change, on an in-session pipeline rewind, and on the next play's start after a session ended without a reset.
  • Mech/WorkpieceController.cs — GET / POST /api/Workpiece/diff-settings: the visual radius, the detection radius the current overlay was built with, and whether one is attached; the POST validates finite-and-positive and writes through the project service.
  • Execution/ExecutionStatusService.cs — the reset counter the branch's rebuild key rides.

HiAPI Engine

  • HiNc/MachiningProcs/LocalProjectService.cs — the app-lifetime bridge that forwards each executed piece and each built machining step, the reset that ends the session, and the DiffVisualRadius_mm facade that writes the authored workpiece, the runtime workpiece and the live colour rule at once, re-seeding the rule from the project's own workpiece on every materialise.
  • HiMech/NcMech/Workpieces/WorkpieceService.cs — HasDiffOverlay, the DetectionRadius_mm the node label is built from, and the Diff that warns and returns false when there is nothing to compare.
  • HiMech/NcMech/Workpieces/Workpiece.cs — the project-level <DiffVisualRadius_mm> element and its 0.1 mm default.
  • HiMech/MachiningProcs/MachiningSession.cs — the retained conversions and the CL-to-NC writeback run that refills them.
  • HiMech/NcParsers/NcWriteback/NcConversion.cs — one conversion: the destination piece stream, its written path and the source-to-destination map the cross-links walk.
  • HiMech/NcParsers/Syntaxs/SyntaxPiece.cs — the executed unit the index is keyed on, and the source line stamped on its sentence.
  • HiNc/SessionCommands/NcFileCommand.cs — the Program File command whose path seeds a placeholder.
  • HiNc/SessionCommands/NcCodeCommand.cs — the NC Code command whose title is the pseudo-path of an inline node and whose text is that node's only source.

See Also

  • Mission Root Panel — the editable twin: the command list this branch reports on. Its Add Command, drag, move, duplicate and delete ops live on the Control Tree rows and act on commands of any kind; the root's own panel is informational — a no-project note when no project is loaded, otherwise the command count with an Add Command prompt while that count is zero, and the run-order hint in either case
  • Execution Page — the page that hosts the four branches, and the transport, canvas and charts the branch's selections drive
  • PostExecutionCommand Panel (Post-Execution) — the Geometry Difference Detection section that produces the result node this branch shows
  • Execution Extended RenderingCanvas Tool Bar — the Execution canvas's own tool bar: the display controls this branch does not carry, among them the Graphic Cache budget
  • Step Variables Branch — the root below this one: the project's step variables and the keys a play registered
  • Block Info Panel — the Step Info column's panel a line click here steers, and what the syntax piece and this branch's index give it
  • Recomputing a Finished Strip — what the Recompute button runs: the change detection that sets its scope, the changes that need a replay instead, and how it shares the player with a play