Skip to content

Restore paused debug state from REST and fix the live event envelope - #782

Merged
Sev7eNup merged 5 commits into
mainfrom
fix/audit-live-debugger
Nov 3, 2026
Merged

Sev7eNup merged 5 commits into
mainfrom
fix/audit-live-debugger

Conversation

@Sev7eNup

@Sev7eNup Sev7eNup commented Nov 3, 2026

Copy link
Copy Markdown
Owner

Last of five stacked PRs (on top of #781). Until the earlier ones are merged this diff also shows their commits; the change of its own is the top commit.

What changes

  • Contract change: GET /api/executions/{id}/paused-steps returns one DebugPausedStepSnapshot per waiting breakpoint (stepId, stepLabel, pausedAt, reason, redacted variables) instead of a list of step ids. IWorkflowEngine.GetPausedSteps becomes GetPausedSnapshots; np exec paused-steps prints label, reason and time; MCP list_paused_steps returns pausedSteps instead of pausedStepIds. The snapshot is a copy of the values the live StepPaused event carried.
  • Reconnect / reload: step hydration in useWorkflowSignalR fetches steps and paused snapshots together, replaces the REST baseline and replays only the events received during that request. After a reconnect every already hydrated run is hydrated again, so gaps from the disconnect close.
  • Overrides: DebugOverrides.Validate is the single check (count, key, size; globals.* and __* rejected). The controller returns 400 and DebugHandle.Resume throws before the pause is consumed, so a rejected override leaves the step paused instead of failing the run after resume.
  • Inspector: drafts are keyed to one pause (stepId:pausedAt) and to the execution; only manual.* and step results are editable.
  • Live envelope: the server's JsonHubProtocol sends {type, event}. Live-Ops/dashboard/execution pages decode it through the shared normalizeBatchItem (they only read Event/evt and fell back to polling), the demo hub sends the real shape, and history pages invalidate after a reconnect.
  • Docs: API workflow control, designer modes, CLI (de/en), docs/workflow-designer-features.md, E2E section 59.

Tests run locally

  • dotnet build NodePilot.slnx: 0 errors
  • dotnet test tests/NodePilot.Engine.Tests --filter Debug|ForEachActivityExecution|WorkflowSchedulerTests (70)
  • dotnet test tests/NodePilot.Api.Tests --filter ExecutionDebug|EndpointClientCoverage (19)
  • dotnet test tests/NodePilot.Cli.Tests --filter NodePilotApiClientResources|ApiDtoParity|Exec (96)
  • dotnet test tests/NodePilot.Mcp.Tests --filter ExecutionControlTools|DocumentationCounts|ToolCatalog (34)
  • Vitest: signalrReducer, useSignalR, useDashboardFeed, ExecutionsPage, execution/debug panels, demo suites (16 files, 285 tests)
  • tsc for app and demo, npm run lint:ci (10 warnings, all pre-existing)
  • Playwright against a local dev server: paused-inspector (59.2 is no longer skipped, it now covers the snapshot inspector), debug-overrides, execution, execution-timeline, execution-retry, executions-list-ui, agent-run-trace, special-scenarios, operations — 44 passed, 9 skipped (pre-existing skips)
  • Documentation site: 227 tests
  • Not run locally: e2e-demo (needs the demo build), covered by CI

Closes #606
Closes #696
Closes #697
Closes #706

🤖 Generated with Claude Code

Sev7eNup and others added 5 commits November 3, 2026 17:24
Renaming an output variable now rewrites every reference through one
traversal (templates in any field, dynamic machine/credential bindings,
breakpoint conditions, decision cases and edge conditions). Copy, paste
and duplicate allocate a fresh alias per copy and rewrite the copy's own
references. The server rejects two active nodes with the same alias,
case-insensitively, and ignores disabled nodes when indexing aliases.

Inserting an activity on a conditional edge keeps the guard in front of
the new activity. Command-palette edge deletion goes through the normal
delete command, and property edits snapshot history before the first
change of a typing burst. Clipboard copies also mask recognised secrets
in edge data and string arrays.

Closes #689, #703, #693, #694, #595. Refs #574.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A save, lock change, publish or run started for one workflow no longer
acts on another workflow opened before it finished: mutations carry the
workflow id they were started for, and completions check the editing
session through the new useAsyncIdentity hook plus the draft generation
in useWorkflowPersistence.

The CRUD editors (credentials, machines, users, global variables,
maintenance windows, custom activities, alerting rules and policies) and
the admin settings sections lock the form while a save is pending and
ignore a late success for a record that is no longer open.

Closes #692, #690.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Property panels follow undo and restored drafts: an edge resyncs its
condition mode and switching to the simple condition clears the
expression; the agent host list adopts restored values. Text-file delete
can select line-range and pattern mode, waitForCondition stores the
displayed portOpen default 443 and flags a missing host or port, and
scheduledTask registration accepts only built-in or managed service
accounts, matching the ServiceAccount logon type the engine uses.

The run-history step details label the shown configuration as the
current draft and show the recorded target machine. The SCCM/AD demo
fixture uses braced interpolation; the example-script harness now parses
every demo fixture script.

Closes #695, #601, #702, #705, #603, #698.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Script generation sends the editor content only to the recipient the
user approved: capabilities expose a recipient key per active profile
(profile id, endpoint, model, sharing switch), the dialog keeps consent
only for that key, and the server rejects a stale key with
409 LLM_RECIPIENT_CHANGED before creating a client. The workflow and
knowledge assistants derive their history context from the same key.

The database viewer runs a write only after the confirmation phrase,
also when Run is pressed again while the dialog is open; the dialog is
a modal with a focus trap. Chat persistence no longer interrupts
sending when browser storage is blocked or full, keeps the newest
history within a size budget and tells the user what survives a reload.

Closes #688, #691, #701.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GET /executions/{id}/paused-steps returns one redacted snapshot per
waiting breakpoint (step id, label, pause time, reason, variables)
instead of step ids, and the CLI and MCP mirror it. The designer
hydrates paused variables from it, replaces the REST baseline on
hydration and replays only events received during the request, and
re-hydrates known runs after a reconnect.

Debug overrides are validated once in DebugOverrides, before the pause
is consumed: globals.* and reserved keys return 400 and the step stays
paused. The inspector keys its drafts to one pause and makes only run
inputs and step results editable.

Live-Ops, the dashboard and the execution pages decode the server's
{type, event} batch envelope through normalizeBatchItem and reconcile
after a reconnect; the demo hub sends the same envelope. E2E 59.2 now
covers the snapshot-based inspector.

Closes #606, #696, #697, #706.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Comment on lines +196 to 200
if (!dict.TryAdd(variable, node.Id))
throw new InvalidOperationException($"Duplicate active output variable '{variable}'.");
}
}

@Sev7eNup
Sev7eNup merged commit da9a432 into main Nov 3, 2026
17 checks passed
@Sev7eNup
Sev7eNup deleted the fix/audit-live-debugger branch November 3, 2026 17:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants