fix(central-ui): Flow Debugger Replay opens to OperationalAudit roles; Live run and Retry/Discard stay Deployer-only (arch-review F3)

Design D6 / §9 says a Live run is a Deployer act while Replay needs only
OperationalAudit, but the page and all three FlowDebug* commands were gated on
Deployer. The Audit Log and Execution Chain pages -- themselves OperationalAudit
-- show an "Open in Flow Debugger" drill-in that an auditor could not follow.

Implements the split:

- New `RequireFlowDebugger` policy over `FlowDebuggerAccessRoles`
  {Deployer, Administrator, Viewer}; the page now carries it instead of
  `RequireDeployment`.
- `FlowDebugReplayCommand` takes the same role set in the ManagementActor
  matrix; `FlowDebugRunMethodCommand` / `FlowDebugRunValueChangeCommand` stay
  DeployerOnly.
- The page resolves `_canLive` (Deployer) in OnInitializedAsync and, without it,
  pins the mode to Replay, hides the entry-point and mode toggles, the Run
  button and the Live pickers, honours only the `?executionId=` drill-in, and
  leaves the parked-node Retry/Discard callbacks unset so those buttons never
  render. `CanRun`, `SetMode(Live)` and `ActOnStepAsync` repeat the check so the
  split does not rest on markup alone.

The NavMenu entry stays inside the Deployer-gated Deployment section -- auditors
arrive through the audit drill-ins, which is the point of the finding.

Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
This commit is contained in:
Joseph Doherty
2026-09-06 14:13:32 -04:00
parent cccef7b2f4
commit f86eb61d1a
8 changed files with 266 additions and 27 deletions
@@ -195,6 +195,11 @@ public class ManagementActor : ReceiveActor
private static readonly string[] OperatorOnly = [Roles.Operator];
private static readonly string[] VerifierOnly = [Roles.Verifier];
// arch-review F3: Flow Debugger Replay is an audit read, so it carries the same role
// set as the RequireFlowDebugger page policy ({Deployer, Administrator, Viewer}). The
// two Live run commands stay DeployerOnly.
private static readonly string[] FlowDebuggerReplayRoles = AuthorizationPolicies.FlowDebuggerAccessRoles;
// arch-review C6: area management is reconciled to any-of [Designer, Deployer].
// Areas are authored on both real surfaces — the Designer template/topology
// tooling AND the Central UI Deployment Topology workflow (Topology.razor is
@@ -305,9 +310,13 @@ public class ManagementActor : ReceiveActor
or RetryParkedMessageCommand or DiscardParkedMessageCommand
or DebugSnapshotCommand => DeployerOnly,
// Flow Debugger (design 2026-09-05 §9): Live runs execute scripts and write attributes
// on operator input, Replay reads the audit chain — Deployer, like the Debug View.
FlowDebugRunMethodCommand or FlowDebugRunValueChangeCommand or FlowDebugReplayCommand => DeployerOnly,
// Flow Debugger (design 2026-09-05 §9 / D6, arch-review F3). A Live run executes
// scripts and writes attributes on operator input, so it stays Deployer-only, like
// the Debug View. Replay only reads the audit chain, so it additionally accepts the
// OperationalAudit roles — the Audit Log / Execution Chain drill-ins are the
// feature's main entry for a past incident and an auditor must be able to use them.
FlowDebugRunMethodCommand or FlowDebugRunValueChangeCommand => DeployerOnly,
FlowDebugReplayCommand => FlowDebuggerReplayRoles,
// Two-person secured write. Submit is an Operator action;
// approve/reject are Verifier actions. Separation of duties (a write may