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"]
Poll["Poll status, watch the run<br>same runId"]
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.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 steps also keep the no-contact warning from firing, so nothing in the second run reports the damage.
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. Keep therunIda real start returns.- Poll
GET /api/Execution/statusuntil it reports thatrunIdwithexecutionStatuseitherFinishedorReady. 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. - 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 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, YieldingStressRatio 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 |
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 program that
never mounts a tool — 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. 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; often the NC messages 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.
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) |
| 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.
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.
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.
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.
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. 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>.
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.
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
- Geometry Validation — the geometry difference behind
hasDiffOverlay