Workflow: Replay Acceptance over the HTTP API
Project Construction ends with a clean replay: the whole mission played, every message read by id, and the numeric cross-checks made. This page is that replay driven over the HTTP API, for a script or an agent with no canvas to look at: how to start a run that really is a fresh one, how to watch it while it plays and know it has ended, and the evidence that it cut what it should.
Sign-in, the reply envelope and the other conventions every route here follows are Driving the Web Service over HTTP.
flowchart LR
Free["Instance free?"]
Reset["Reset"]
Start["Start<br>keep runId and instanceId"]
Poll["Poll status, watch the run<br>same runId, same instanceId"]
Evidence["Read the evidence"]
Msgs["Inventory messages"]
Free --> Reset --> Start --> Poll --> Evidence --> Msgs
Msgs -->|fix, then replay| Free
1. Start from a free instance and a reset session
The service holds one project and one run for every client connected to it, so a replay begins by checking that the instance is free, and never ends by stopping a run it cannot prove is its own.
GET /api/Execution/status. IfexecutionStatusisRunningorPaused, a run is live — do not start, reset or stop it. A reset stops a live run too. Areviewthat is notnullis a recorded play open for review (§7), possibly another client's: no program plays while it is open — the first program a run reaches ends it withPlayer-Run--Fault— and the Reset of step 2 closes it.POST /api/Execution/reset, before every start. Start does not reset. After a finished run,POST /api/Execution/startplays the mission again on top of the session that run left behind — the machined workpiece, its steps and its messages. Every Read On First Or Write record then sees steps already produced and writes instead of reading, so the stage-0 record overwrites the cached stock with the machined part, and every later run, reset or not, starts from stock that has already been cut until that file is deleted. The earlier run's touching steps also keep the no-contact warning,Play-Touch--None, from firing; what the second run reports instead is aTool-Touch--Nonefor each tool that cuts nothing, which points at tool lengths and offsets, not at the skipped reset. While another request plays an NC program on the session — aPOST /api/SessionShell/PlayNcFile, for one, whichexecutionStatusdoes not show asRunning— the reset answers409withcode: "Reset--Busy"and resets nothing: wait for that play to end, then reset.
A reset empties the step strip and the session's message lists, so read the evidence of the previous run (§4, §5) before resetting for the next one.
2. Start, and poll by run id
POST /api/Execution/start, then check the body, not only the status code. An enabled Script command that does not compile refuses the start with HTTP 200,success: falseandcode: "script_compile_error"; a start while a run is live answersalreadyRunning: trueand starts nothing, and therunIdbeside it is the live run's — the service cannot tell whether it is yours, so do not poll for it. Keep therunIda real start returns and theinstanceIdbeside it, the service process therunIdcounts in. A real start also says whether it began on a fresh session:continuesSession: true, with anotesaying so, means the Reset of §1 was skipped and the run plays on top of the session an earlier play left, so its evidence will hold that play's steps and messages too. Accept nothing from such a run: it is yours, so reset — which stops it — and start again. A start on a fresh session answerscontinuesSession: false.- Poll
GET /api/Execution/statusuntil it reports thatrunId, under the sameinstanceId, withexecutionStatuseitherFinishedorReady. After a Reset,Readyis how a run that was stopped, or that ended in an exception, reports itself: a poller that waits forFinishedalone never returns from a failed run. Without the Reset of §1, such a run inherits the previous run'sFinished. The exception behind aReadyis in the service log, whichGET /api/Project/logsreturns for the current day. A higherrunIdmeans another caller has started a run since. A differentinstanceIdmeans the service restarted and the run is gone: a new process counts its runs from 1 again. - Read the evidence below before anything resets the session.
Watch it while it plays
A long play is worth watching while it runs, not only judging at its end. A wrong program zero, a tool length or offset set wrong, or stock in the wrong place does not stop a run: it keeps colliding, cuts air or cuts too deep for hours, and every program played on that stock afterwards is wasted. The requests below read the live run, change nothing, and are cheap enough to repeat every few minutes while the poller waits:
| Look at | Request | Healthy |
|---|---|---|
| Still running, still yours | GET /api/Execution/status |
executionStatus is Running with the runId and the instanceId your start returned |
| Progress | GET /api/execution/cl-strip/range |
count grows between two looks |
| Alarms | GET /api/Execution/messages?minSeverity=Message&tail=0&idPrefix=<prefix> for Collision-- and Play-RapidCut, and with minSeverity=Error for Stroke (which leaves out StrokeLimit--Unconfigured, a one-time set-up warning at the start) |
every list's matched stays 0 |
| New warnings | GET /api/Execution/messages?minSeverity=Warning&tail=1000 |
no id you have not accounted for (§5) |
| Where the play is | the strip chart of §4 with widthHint=0, dispBegin a stretch before count, dispEnd=<count> and inspectingKey FileNo, LineNo, ToolId, Cl.X, Cl.Y, Cl.Z, read at its last value that is not NaN — count includes steps still being computed, which answer NaN |
the file and line move on; the tool is the one the program calls, where the program cuts |
| Cutting, and how hard | the same chart over the last few thousand steps, with IsTouched, CuttingDepth_mm, MaxAbsForce_N, StressRatio and MaxSpindlePowerRatio — the last three are physics: with the project's physics off, no physics licence, or Show Physics Options off they answer NaN or an empty items |
in contact where the program cuts; depths within the tool's length of cut — near the step-down only where no wall is engaged, since a wall, a corner or a flank pass engages up to the whole length of cut (§6); stress and spindle-power ratios below 1 |
The strip chart's Individual aspect answers the project's inspecting key alone (HiNC 3.2.46 and
later): post the key first — keep the key the project holds (inspectingKey of GET /api/execution/strip-chart-item-config without a key), then POST /api/execution/inspecting-key with {"inspectingKey": "FileNo"},
whose reply's currentKey must be the key — then read. An answer with pending: true is not ready:
the host is still filling that key's values for every step, so read again after a moment until it is
false; items empty with pending: true means the key is not the project's (another client posted
its own). Posting a key changes the project's own setting, which a save keeps, so when the reads are
over read it again and, while it is still the key you posted, post back the key the project held
before, the one you kept; a
key another user has set since is theirs to keep. With tail=0 each list answers its total and the matched
count for the filter without returning the messages, so an alarm check costs one small reply per
prefix. The canvas of the app, looked at
during the play without selecting a step, shows the tool and the stock as cut so far; the geometry
difference is built only when the play ends.
Stop a play only for a set-up error that spoils what follows — alarms that keep coming, no contact
where the program should cut, depths or loads far beyond the pass, a tool somewhere the program never
goes. Then stop it (POST /api/Execution/stop stops whatever run is current, so only a run you know
is yours), fix the set-up, and replay from §1. A defect that does not spoil what follows — a warning
already understood, a single touch on a retract — is written down and the play left to finish; it is
judged with the rest of the evidence in §4 and §5.
If the poller gives up, let it give up: a timeout is not a reason to call
POST /api/Execution/stop. It takes no run id and stops whatever run is current, which on a shared
instance may not be yours, and a stopped run ends without the rows below the point it reached — no
Post-Execution output, no end-of-stage record.
3. Coarse first, then fine — and clear the stock cache in between
The first plays of a new project check datums, not surfaces, so they run at a coarse Initial
Resolution (PUT /api/Workpiece/init-resolution) and a coarse Machining Resolution. Moving to the
fine resolution for the acceptance run has one trap. The stage-0 record above the first program
caches the stock as it was meshed at the Initial Resolution of that time, and every later run reads
that file back — so after changing the Initial Resolution, the stock geometry or its allowance, the
next run starts from the old stock and nothing says so.
Delete the stage-0 file before the next start:
DELETE /api/Mission/commands/{path}/recordmeshedgeom/file, with {path} the record's entry path
(GET …/recordmeshedgeom/file-status reports whether the file exists). An end-of-stage file you mean
to resume from was written at the old width as well; delete it or play its stage again. A change to
the Machining Resolution command needs no deletion — it governs the cuts below it, not the cached
stock. A Mission That Resumes is the layout these records
belong to; in the app, the record's own Reset deletes its file.
4. A finished run is not a passing run
Finished says the mission reached its end. It does not say that anything was cut. A session
starts with no tool in the spindle unless the project saves one with its equipment — no route of
this API sets one, so a project built through it never does — and from then on only a tool-change
command or a Manual Tooling entry mounts a tool. A program that never mounts one — written for a
machine whose operator changes tools by hand, with no T… M06 in it; a tool word the runner could
not resolve; an empty tool-name table — plays every line, produces no machining steps at all,
and still ends Finished. In the step list it leaves one warning, Step-Tool--NotEquipped, at
the first feed move made with the spindle empty, naming that move's line and file — once per
Reset. The end-of-play warning Play-Touch--None is raised only when steps exist and none of them
touched the stock, so a play with zero steps never reaches it; and the NC messages often carry no
trace of it at all — a G43 H1 compensates from the table whether or not a tool is in the spindle,
and a G43 with no H runs on the modal H (H0 until one is written) without a word, as the
control does.
Give such a program its tool before the cuts, as the operator does. First choice: a Manual Tooling
entry above its Program File — POST /api/Mission/list-command/entries with
{"commandType": "manualtooling", "insertIndex": <the Program File's index>}, then
PUT /api/Mission/commands/{path}/fields/toolId with the tool number as the body. It mounts the
tool and plays nothing, so the file keeps its lines and its file number
(Mounting the tool the operator loads by hand).
Otherwise put the change at the start of the copy the project plays
(Project Construction §1) — T1 M06. An NC Code entry holding the
change above the Program File mounts the tool too, but it is played as a file of its own, so it
takes a file number and every program after it moves up one: a controller log mapped by FileNo
(Sensor Mapping) has to follow. A program with no G43 needs the tool's
length as well — a G43 H for the tool in the copy, or the length folded into the work offset's Z
the way a shop without length compensation keeps it
(Program Zero Alignment).
Without it the tip runs a whole tool length below every programmed Z, and the play either touches
nothing, ending with Play-Touch--None, or plunges that far into the stock.
A zero-step run also hides behind the resume layout. With no step produced, every Read On First Or Write record below the program still reads, so an end-of-stage file left by an earlier good run is loaded back — and the canvas and the geometry difference show that earlier result as if this run had made it.
So accept a replay on evidence:
| Check | Request | Pass |
|---|---|---|
| Steps exist | GET /api/execution/cl-strip/range |
count > 0 |
| Something was cut | GET /api/execution/strip-chart?aspect=Individual&inspectingKey=IsTouched&xValueCategory=IndexByStep&widthHint=1&dispBegin=0&dispEnd=<count> |
the largest value in items[0].max is 1 |
| Every program ran | GET /api/NcProgram/files |
every file — and every subprogram, listed under its caller's children — has an invocation with a non-zero executedLineCount |
| The difference was built | GET /api/Workpiece/diff-settings |
hasDiffOverlay is true (and detectionRadius is no longer null) |
| Outputs written | GET /api/Execution/messages?kinds=shell&idPrefix=StepFile-&tail=1000 (and idPrefix=ShotFile-), then GET /api/file-explorer/list?rootName=ProjectDirectory&relativePath=<the template's folder> |
a StepFile-Create--Start (ShotFile-Create--Start) row, Creating file[…], for every file expected, between the writer's …-Write--Start and …-Write--Finish; no …-Write--NoFile; every file listed, with a size above 0 |
| Messages | GET /api/Execution/messages |
every id accounted for (§5) |
GET /api/Workpiece/diff-settings answers { hasWorkpiece, diffVisualRadius, detectionRadius, hasDiffOverlay }, and { hasWorkpiece: false } with no project loaded. hasDiffOverlay says an
overlay is attached to the live meshed tree right now — not that deviations were found, and not
that a comparison was requested — and detectionRadius is null until one exists, so a null
radius is the same answer as a false flag. A Reset clears both.
A Post-Execution writes only what has played above it. A writer of it that opened no file — the
command sits above the programs, or the run has no steps — ends on StepFile-Write--NoFile or
ShotFile-Write--NoFile, a warning, instead of …-Write--Finish. The path in a Creating file[…]
row is the template expanded, relative to the project folder unless the template is absolute; a
folder that was never created answers the file-explorer list with 404.
Pass dispBegin and dispEnd explicitly: without them the strip chart covers only the window
currently on display, not the run. widthHint=1 returns at most two points: the first covers the
range without its last step, the second the last step alone. Take the range's peak as the largest
value in items[0].max (and its floor as the smallest in items[0].min); widthHint=0 returns
one point per step instead. Post the key first (§2): the request answers IsTouched only while it is
the project's inspecting key, and pending: true until the host has filled its values.
For a line whose effect you doubt, GET /api/NcProgram/syntax-piece?fileIndex=<i>&lineIndex=<n>
returns the sentence as the runner parsed it, together with the steps it produced — the direct way to
see which command an address word was attached to. Under a review (§7) it answers the block recorded
at that file and line — the first one recorded there — in the same JSON, with the steps rebuilt from
it; a query by sentenceIndex alone finds nothing.
5. Inventory the messages
GET /api/Execution/messages returns one section per list — shell, nc, step and ncManip —
and filters them all the same way:
minSeverity=Warning&head=50returns the first matches, which is where the cause of a cascade sits; the default takes them from the end.tailis capped at 1000, andtail=0returns counts only — the quick way to size each list.idPrefixnarrows to one family of ids;kindsnames the lists to read.sinceIndexpages one list at a time, sokindsmust then name exactly one.
A Collision--Detected's stepIndex is the index its pose's step takes, and it is reported the
moment the collision is found, before that step is built; a run that pauses on failures pauses
right there. The licence and lease refusals said before a step is granted
(MachiningStep--LicenseCapReached and its kin, which hold the run), Player-Run--Fault and
Step-Task--Fault (a step whose building failed) are anchored to their own step the same way. So is
a stroke-limit report — Stroke-Limit--Over, or StrokeLimit-Xyz--Over and StrokeLimit-Abc--Over
on the legacy HardNc runner — on the step whose pose went past the limit (for a motion that built no
step, the index that step would have taken); it names no sentence, so its sentenceIndex is -1.
After a stop and a start without a reset, the replay's steps take the numbers on from
there, so the same index can belong to a later step. To tell, ask
GET /api/NcProgram/sentence-of-step?stepIndex=<stepIndex>: the step is the message's only when
the answer's sentenceIndex equals the message's. Without a sentenceIndex, an index below
stripCount while locked is a position the pipeline is still filling (ask again); the next index
(notBuiltYet) while running is the step the run is building; notBuiltYet otherwise is a step
the run stopped or paused before building; an index below stripCount with nothing locked is a
step a stop dropped or whose building failed. The other step messages — a script's, a tool
change's, a line end's, an empty spindle's — are anchored to the next built step by design and are
not compared; a message whose sentenceIndex is -1 has nothing to compare. The comparison holds
within one numbering of the sentences: a reset clears the messages, while an EndSession, a
script's PowerReset() or a change of the NC runner keeps them and numbers the next sentences from
zero again. Under a review (§7) sentence-of-step reads a recorded step as it reads a live one, but
the result keeps no messages: the lists hold only the review's own, and there is nothing to compare.
What to stop on — only declared informational messages, plus the expected messages of constructs left as delivered — is Project Construction §5.
6. Figures for the cross-checks
The strip-chart request of §4 returns the peak of any step property over any step range — the
largest value in items[0].max across the points it returns — once that property is posted as the
inspecting key (§2). Take the
keys from GET /api/execution/step-properties — CuttingDepth_mm for the depth-of-cut check,
MaxAbsForce_N for a force peak. The depth peak of a roughing group should match its step-down; that
of a finishing program is not its allowance, since a wall or a corner can engage the whole length of
cut — check a finishing job's Z datum with the distance test of
Building the Workpiece from a Reference Mesh §1 instead. A run at
a machining resolution coarser than the allowance says whether the program touches the stock and
where; take its forces and depths only from a run at a resolution finer than the allowance. To narrow the range to one file, take the invocation's
firstSentenceIndex and lastSentenceIndex from GET /api/NcProgram/files and turn each into steps
with GET /api/NcProgram/steps-of-sentence?sentenceIndex=<n>. Under a review (§7) the invocations carry
no sentence range and steps-of-sentence answers found: false: a line's steps are in its
line-marks entry and its syntax-piece answer instead.
The simulated time at the end of step i is its end time code:
xValueCategory=IndexByTime&widthHint=0&dispBegin=<i>&dispEnd=<i+1> returns it in xs, in seconds.
The difference across a file's step range is the time to compare with the post-processor's estimate,
with the limits Project Construction §6 sets on that comparison.
7. A recorded play, reviewed over the API
A play recorded with Record Play Result can be read again without playing it
(Recording the play and reviewing it).
POST /api/LocalProjectService/OpenNcResultReview?relResultDirectory=<folder> opens the review — the
folder relative to the project folder, empty for the newest completed result — and
POST /api/LocalProjectService/CloseNcResultReview closes it. Both need a loaded project but no
session, and answer 200 when the review opened or closed and 409 when it did not, with the reason
among the body's messages; a folder that holds no result file answers 500. Opening ends a recording
still open and resets the run first, as the Reset of §1 does, so read a live run's evidence before
it; a Reset, a Close and a project switch close the review.
While it is open, GET /api/Execution/status carries review — the folder, the program's name, when
it was recorded, its step, position and block counts, whether the recording was completed and the
play ran to its end, and what became of its finished stock (wctState, and wctColoured: whether the
loaded stock is coloured and picked by the recorded steps, false for a result recorded without the
stock's node map, which shows it plain) and of its luggage archive (luggageState: Loaded when the
folder's luggage.db — the recorded steps' force arrays and engagements — is open, None when the
folder holds none, Incomplete, Mismatch or Failed when the review did not read it) — and
null when none is open. The strip, the steps and the strip charts are the recorded ones, and so
are the two Sim cycle charts while luggageState is Loaded:
GET /api/execution/cycle-line/force and GET /api/execution/cycle-line/sim-spindle-moment answer
from the archive as during the play. What the result does not hold answers ready with no data
rather than pending: the CWE panel's POST /api/Execution/step-volume/{connectionId} in every
review, and the two Sim cycle charts without an archive or for a step it does not hold, carry
reviewing: true, which the app shows as Not in the play result, and the steps have no
step-variable values. The Program requests answer from the result file: files lists one root per
recorded source file, without a caller, a sentence range or an executed-line count (-1);
line-marks marks a line where a pass recorded a block, with its steps; syntax-piece (§4),
sentence-of-step (§5) and steps-of-sentence (§6) answer as said there. The result keeps no
messages and no executed-line counts, so the checks of §4 that read them are a live run's.
See Also
- Project Construction — the build this replay accepts
- Driving the Web Service over HTTP — sign-in, reply envelope, one service with one project
- A Mission That Resumes — the record layout and when its cache goes stale
- When Something Goes Wrong — the message lists as the app shows them, and a finished run with nothing to show
- The Other Commands — Post-Execution: what it writes, where, and how it reports each file; Record Play Result and Review Play Result
- Geometry Validation — the geometry difference behind
hasDiffOverlay