Commit Graph

1683 Commits

Author SHA1 Message Date
Joseph Doherty befb0e3805 feat(commons): FlowTraceCollector low-priority lane for log lines (D7) 2026-09-09 11:26:05 -04:00
Joseph Doherty 50eca87e99 Merge branch 'worktree-agent-a327a30cdb2e454ff' into feat/instance-picker 2026-09-08 10:01:47 -04:00
Joseph Doherty 52726cf30d fix(central-ui): Debug View reconnect guards the stored instance; drop select-era sort; deep-link-in-area test
Three final-review findings on the two picker pages:

1. DebugView's localStorage auto-reconnect restored the stored instance id with
   no membership check, where the ?instanceId= path has one — a stored instance
   that is no longer Enabled (or was deleted, or moved sites) is filtered out of
   the list the picker is handed, so the field rendered blank while the page held
   a non-zero id and auto-connected to it anyway. The guard now mirrors the
   deep-link path: forget the stored instance id, tell the operator, and leave the
   site selected and loaded so they can pick again.
2. FlowDebugger's _instances kept an OrderBy(UniqueName) from the flat <select>
   era; InstanceTreeBuilder sorts areas and instances itself.
3. The deep-link test is joined by one where the instance sits two areas deep, so
   the field text is pinned to resolve from the flat list with the panel never
   opened.

Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
2026-09-08 10:01:22 -04:00
Joseph Doherty a33a2f4456 fix(central-ui): InstancePicker — keyboard activation selects/toggles through TreeView selection; aria-label/InputId; aria-controls only while open
ArrowDown moved focus into the tree, but the picker passed no Selectable /
SelectedKeyChanged, so Enter/Space on a treeitem only moved the roving tabindex —
the pick lived on the label span's @onclick, i.e. mouse only. The tree now runs in
Selectable mode and BOTH gestures arrive at one handler (OnTreeKeyActivatedAsync)
through TreeView's SelectedKeyChanged: an `i:{id}` key selects that instance, an
`a:{id}` key toggles the branch. The label's own @onclick is gone — the click
already bubbles into TreeView's content span, so a second handler there would fire
the callback twice. SelectedKey stays unbound (a combobox shows its pick in the
field, not as a row highlight, and binding it would arm TreeView's
selected-key-not-in-tree reset on every render while the pick is filtered out);
SelectedCssClass is emptied to match.

a11y: the field gains an accessible name via a new AriaLabel parameter (default
"Instance") and an optional InputId so a page can point a <label for> at it;
aria-controls is rendered only while the panel exists, instead of always pointing
at an id that is absent when closed.

Also drops the unused @using of Commons.Entities.Instances from the .razor.

Tests: keyboard activation on an instance row and on an area row, a
one-selection-per-gesture guard across mouse and keyboard, and the labelling
assertions. CentralUI suite 1331 passed / 0 failed; build 0 warnings.

Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
2026-09-08 10:00:17 -04:00
Joseph Doherty 82f6fb949e fix(central-ui): keep the instance picker disabled until the site's instances have loaded (typing raced the load and was wiped)
Both Flow Debugger and Debug View enable the shared InstancePicker as soon as
_selectedSiteId lands, but Blazor renders at the site-change handler's first
await — at which point the picker is still holding the PREVIOUS site's Areas /
Instances lists. Typing into the field in that window (an operator, or
Playwright's FillAsync, which waits only for "enabled") was silently lost: the
picker compares both lists by reference, so the freshly-assigned lists read as
"the site changed" and it clears the field text and closes the panel.

Both pages now hold an _instancesLoading flag across the whole load — set before
the first await, cleared in a finally so a fault or a site-scope refusal cannot
leave the picker disabled forever — and fold it into the picker's Disabled
expression. InstancePicker itself is unchanged.

Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
2026-09-08 09:58:44 -04:00
Joseph Doherty d3264ec1b1 Merge branch 'worktree-agent-a24fb696f5eee22f2' into feat/instance-picker 2026-09-08 09:49:19 -04:00
Joseph Doherty 8047de6903 fix(central-ui): Flow Debugger picker — site change clears the pick (test); wider column, shorter placeholder
Pins the site-change behaviour the picker's reference contract exists for: after
picking an instance, switching the site select empties both the page's
_selectedInstanceId and the picker's field text (the new site hands it a
different instance list), and leaves the script select on its placeholder.

Layout: the Instance column goes col-md-2 → col-md-3 so a full instance name
fits — the script-entry branch still sums to 8 of 12 (site 2 + instance 3 +
script 3), and Method never renders beside them — with the placeholder
shortened to "Search instances…" for the narrower field.

Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
2026-09-08 09:49:05 -04:00
Joseph Doherty f32f08a4c7 Merge branch 'worktree-agent-a9d87141c744e7733' into feat/instance-picker 2026-09-08 09:48:25 -04:00
Joseph Doherty a0292d3063 fix(central-ui): Debug View picker — disabled-while-connected test; drop no-op handler; static label
Task 5 review follow-ups:

- New DebugViewInstancePickerTests.WhileConnected_ThePickerIsDisabled pins that
  a live connection locks the picker: both the input and the chevron carry
  `disabled`. It marks the page connected by reflection, the way the other
  DebugView page tests do (DebugViewAlarmTableTests) — driving the real gRPC
  stream is not available to a bUnit render.
- OnInstanceSelectionChanged() was already a no-op and its comment described the
  @bind that the picker replaced; deleted, and OnInstancePicked now just records
  the id (XML-documented).
- The ItemLabel lambda is hoisted to a private static InstanceLabel(Instance),
  passed as a method group.

Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
2026-09-08 09:48:13 -04:00
Joseph Doherty 2ec0e63671 Merge branch 'worktree-agent-acdd9dc794506dee9' into feat/instance-picker 2026-09-08 09:45:55 -04:00
Joseph Doherty dd751be917 test(playwright): Flow Debugger instance row matched through the data-test contract
The instance row locator used Locator.GetByText scoped to the panel, which
bypasses the [data-test='flow-instance-row'] contract InstancePicker rows
are documented to carry. Match through the data-test attribute instead,
with an exact-text regex since the test only knows the instance name (not
its id, unlike Debug View's tests).

Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
2026-09-08 09:45:41 -04:00
Joseph Doherty a9db239075 Merge branch 'worktree-agent-af2a6023106279956' into feat/instance-picker 2026-09-08 09:45:38 -04:00
Joseph Doherty cccc6e82d2 Merge branch 'worktree-agent-a24fb696f5eee22f2' into feat/instance-picker 2026-09-08 09:45:25 -04:00
Joseph Doherty dfdf480fa1 test(central-ui): InstancePicker — closed-panel ArrowDown, Escape no-op; dispatcher-ordering and overflow notes
ArrowDown on a picker that has never been opened pins the deferred path where
_tree is still null when the keydown is handled: the panel opens in that render
pass and the roving tab stop lands on the first row in the next one. Escape on a
closed picker is pinned as a no-op.

Two notes, no behaviour change: FirstVisibleInstance records WHY it may trust
TreeView.IsExpanded (Blazor Server's single renderer sync context runs the render
plus the pending ExpandAll/CollapseAll before the next keydown is dispatched — an
await that genuinely yields inside OnAfterRenderAsync would break that), and the
stylesheet warns integrators that the absolutely-positioned panel is clipped by
any ancestor with overflow: hidden/auto.

The ArrowDown focus interop assertion is kept — it was stable across repeated
runs — with a comment marking the tabindex as the behavioural check.

Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
2026-09-08 09:45:15 -04:00
Joseph Doherty 0f97317933 feat(central-ui): Flow Debugger picks the instance through InstancePicker
The script entry's flat instance <select> is replaced by the shared
InstancePicker combobox (design 2026-09-08 §3): the site's areas load
alongside its instances in LoadInstancesAsync and are held in fields, so the
picker sees one stable list reference per site and only closes its panel on a
real site change. Picking a row raises the id, which OnInstancePickedAsync
applies before running the unchanged OnInstanceChangedAsync — the deep link,
the localStorage restore and the site-scope gate are untouched.

Tests: the five instance-select .Change("7") call sites go through a
PickInstance helper (open the panel, click the data-instance-id row), plus a
new test that areas open collapsed and only reveal the instance once both
levels are expanded, and one that ?instanceId= shows the instance name in the
picker field.

Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
2026-09-08 09:45:07 -04:00
Joseph Doherty 740f5fa6da Merge branch 'worktree-agent-a9d87141c744e7733' into feat/instance-picker 2026-09-08 09:44:43 -04:00
Joseph Doherty 1d622f536d feat(central-ui): Debug View picks the instance through InstancePicker
The flat instance <select> on Debug View is replaced by the shared
InstancePicker area-tree combobox (design 2026-09-08 §3): the page now loads
the site's areas alongside its Enabled instances in LoadInstancesForSite and
hands both lists to the picker with ItemLabel = "UniqueName (State)",
Disabled="@_connected" and DataTestPrefix="debug-instance".

Both lists are now REPLACED rather than cleared in place wherever the site
changes (LoadInstancesForSite, StartFresh) — the picker compares Areas and
Instances by reference and a new object is what tells it the site changed.
The ?siteId=/?instanceId= deep link and the localStorage reconnect keep
setting _selectedInstanceId directly; the picker reads it on parameter set,
so both paths are unchanged.

Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
2026-09-08 09:44:26 -04:00
Joseph Doherty 07c5d53f39 test(playwright): drive the instance picker on Flow Debugger and Debug View
Flow Debugger's script-entry instance selection and Debug View's instance
selection both go through the shared InstancePicker combobox now instead of
a flat <select>. Update the tests to type into the {prefix}-input, wait for
the matching {prefix}-row, and click it; keep the <select>-polling helper
for the site select, which is unchanged.

Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
2026-09-08 09:43:37 -04:00
Joseph Doherty 3c3a7cbbc1 fix(central-ui): InstancePicker — field above the backdrop; site change always closes; reference contract documented; tests
Three Task 2 review findings:

1. The outside-click backdrop is a fixed full-viewport layer at z-index 1040,
   but the input-group was unpositioned — so once the panel was open a click on
   the field or the chevron hit the backdrop and closed the panel instead of
   letting the operator keep typing. The field now carries .ip-field
   (position:relative, z-index 1042), stacking backdrop < panel < field. Pinned
   in bUnit by the class (the z-index itself is scoped CSS, verified visually).

2. OnParametersSet closes the panel on ANY lists change, not only when the
   selection disappeared: an open panel is showing the previous site's tree,
   which is wrong even when the selected instance happens to exist in both.
   The reference-equality contract on Areas/Instances is now stated on both
   parameters — pass a stable reference, replace it only when the set changed.

3. Tests: the chevron closes an open panel; two pickers mint distinct panel ids
   (and matching aria-controls); an unrelated parameter change with the SAME
   Instances reference leaves a half-typed filter and the open panel alone.

Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
2026-09-08 09:39:46 -04:00
Joseph Doherty 621d6bfd94 feat(central-ui): InstancePicker search filter + keyboard (Enter/Escape/ArrowDown)
Typing in the field is the filter: the forest is rebuilt to the matching
instances plus their ancestor areas and force-expanded so every match is on
screen; clearing the text restores the full forest, collapsed. Both bulk
expansions are deferred to OnAfterRenderAsync, because the TreeView only exists
once the panel has rendered.

Enter picks the first instance the operator can actually SEE — document order,
descending into a branch only when the tree reports it expanded — so with areas
collapsed it picks the first root instance, and with a filter (every branch
expanded) it degrades to plain document order. Escape closes and restores the
field text from the current selection; ArrowDown hands keyboard navigation to
the tree via a new additive TreeView.FocusFirstVisibleAsync(), which reuses the
existing roving-tabindex _focusNeedsApply path rather than adding a second
focus mechanism.

No preventDefault: Blazor's flag is all-or-nothing per element, and neither
default is harmful (Enter in a text input outside a form does nothing,
ArrowDown just moves the caret) while suppressing Tab would trap the control.

Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
2026-09-08 09:37:44 -04:00
Joseph Doherty 05e4f3ca0f Merge branch 'worktree-agent-a6cee26f4fe0abdd1' into feat/instance-picker 2026-09-08 09:29:45 -04:00
Joseph Doherty ba1ac38333 feat(central-ui): InstancePicker — combobox over the site's area tree
A shared Bootstrap-only combobox that replaces the flat instance <select> on
Flow Debugger and Debug View (design docs/plans/2026-09-08-instance-picker-design.md,
plan task 2): a text field over a dropdown panel hosting TreeView across the
InstanceTreeBuilder forest, every area collapsed on open. Clicking an area row
toggles it, clicking an instance row selects it, closes the panel and raises
SelectedInstanceIdChanged. Outside clicks close through a transparent fixed
backdrop — the same pattern TreeView uses for its context menu, so no JavaScript.

A site change (new Areas/Instances references) closes the panel and clears the
field when the selection no longer resolves; a parent-driven SelectedInstanceId
change re-derives the field text while closed. ItemLabel customises row and field
text (Debug View wants a "(State)" suffix) while search still matches UniqueName.

TreeView gains one additive public ToggleExpanded(key) — the chevron's existing
private toggle, exposed so a consumer whose own NodeContent owns the label click
can toggle the branch.

Search filtering and keyboard handling land in task 3; _filter/Rebuild() are in
place for them.

Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
2026-09-08 09:29:21 -04:00
Joseph Doherty 8e6b748029 fix(central-ui): InstanceTreeBuilder — orphaned instances surface at root; read-only Children; edge tests
Review follow-ups on f12ba2f9:
- An instance whose AreaId points at an area outside the supplied list was
  silently dropped; it now surfaces at the root, mirroring the orphaned-area
  rule, and stays filterable.
- InstanceTreeNode.Children is an IReadOnlyList over a private backing list,
  composed by the builder through an internal AddChild — the record no longer
  hands callers a mutable list.
- Extra tests: unknown-area instance (root + filterable), 3-level nesting,
  a ParentAreaId cycle that must neither loop nor throw, and a filter that
  matches instance names only (an area name match alone does not keep it).

Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
2026-09-08 09:26:14 -04:00
Joseph Doherty f12ba2f9eb feat(central-ui): InstanceTreeBuilder — area/instance forest for the instance picker
Task 1 of the Instance Picker plan (docs/plans/2026-09-08-instance-picker.md).
Pure, DI-free builder that nests a site's areas by ParentAreaId and hangs each
area's instances beneath it, mirroring Topology's ordering (child areas first,
then that level's instances; OrdinalIgnoreCase sorts) with unparented instances
at the root after the root areas. Orphaned areas become roots, a case-insensitive
filter keeps matching instances plus their ancestors and drops empty branches,
and a ParentAreaId cycle can never recurse forever.

Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
2026-09-08 09:22:11 -04:00
Joseph Doherty 859922ba17 fix(central-ui): Flow Debugger spawn edges — real arrowhead + bolt badge; spawner picked by trigger attribute
The trigger-cascade (Spawn) edge used a lightning-bolt marker IN PLACE of the arrowhead. On the upward
Tags→Site hop the bolt sat on top of the riser and read as a broken arrow (rig screenshot 2026-09-08).
Every connector now ends in an ordinary arrowhead; the bolt is a badge (circle + bolt) centred on the
connector's vertical run (FlowGraphView.SpawnBadgePoint, kept in step with OrthogonalPath/AsyncPath).

Same screenshot, second defect: the cascade spawned by "RecipeDownloadFlag = false" was drawn from the
LAST write of the burst (RecipeProcessedFlag) because all four writes share a millisecond and the
spawner rule was time-only. FlowGraphBuilder now prefers the parent's last AttributeWrite of the attribute
the child's triggerAttribute names (at or before the child, else the last such write); the time/position
rules remain the fallback when the child names no attribute or the parent never wrote it.

Verified live on the rebuilt rig (DelmiaSim01 / DelmiaReceiverSimulator): both spawn edges show an
arrowhead + badge, the second one originates from the RecipeDownloadFlag write. bUnit + builder tests
updated/added; Playwright FlowDebuggerTests 4/4.

Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
2026-09-08 09:04:39 -04:00
Joseph Doherty 7792b76b12 Merge branch 'worktree-agent-a33b0136b18715bde' into feat/flow-debugger-script-entry 2026-09-08 01:42:42 -04:00
Joseph Doherty ca9be68d91 fix(management): FlowDebugRunner — transport faults still write the root row; write-kind completion is script-specific; standby/unreadable-trigger tests
Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
2026-09-08 01:42:17 -04:00
Joseph Doherty 7197c3986f fix(central-ui): FlowDebugService — re-flatten on each instance selection; safe Ask fallback
Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
2026-09-08 01:41:14 -04:00
Joseph Doherty a2bfc79e3a fix(central-ui): Flow Debugger — remount ParameterValueForm per script so stale form state cannot block Run
Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
2026-09-08 01:32:29 -04:00
Joseph Doherty d9d8fdde05 Merge branch 'worktree-agent-aa4aca38eb138ea83' into feat/flow-debugger-script-entry 2026-09-08 01:29:38 -04:00
Joseph Doherty 0887c69500 test(rig): flow debugger script entry — Playwright direct-call run + verify-delmia-notifier step H2
Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
2026-09-08 01:29:10 -04:00
Joseph Doherty a4e8518e69 fix(management): FlowDebugRunner.RunScriptAsync — always write the root row after a routed call; timeout + unserializable-return tests
Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
2026-09-08 01:27:44 -04:00
Joseph Doherty 11d32335af Merge branch 'worktree-agent-ac243fcc404f04015' into feat/flow-debugger-script-entry 2026-09-08 01:23:36 -04:00
Joseph Doherty e1865f9ab3 fix(central-ui): FlowDebugService — reuse the runner's default script timeout, warn on flatten failure, pin one-flatten memo + parameter threading
Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
2026-09-08 01:23:18 -04:00
Joseph Doherty 9404ff87ca Merge branch 'worktree-agent-a6dd4922425ca12c2' into feat/flow-debugger-script-entry 2026-09-08 01:21:55 -04:00
Joseph Doherty 6fe67e147c feat(central-ui): Flow Debugger script entry — site/instance/script picker, value field or ParameterValueForm by trigger kind
Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
2026-09-08 01:21:30 -04:00
Joseph Doherty e5ca703714 Merge branch 'worktree-agent-a5a04e3ef680c61db' into feat/flow-debugger-script-entry 2026-09-08 01:19:07 -04:00
Joseph Doherty 3f4fde3e35 feat(management): dispatch FlowDebugRunScriptCommand (Deployer-only, long-running) on the ManagementActor
Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
2026-09-08 01:18:52 -04:00
Joseph Doherty b74d3f4de9 Merge branch 'worktree-agent-abbb97d8899ed576d' into feat/flow-debugger-script-entry 2026-09-08 01:17:43 -04:00
Joseph Doherty 45c6b27d99 fix(cli): flow-debug help text names the script entry; replay role note; run-script guard tests
Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
2026-09-08 01:17:32 -04:00
Joseph Doherty 51ce72404b Merge branch 'worktree-agent-a33b0136b18715bde' into feat/flow-debugger-script-entry 2026-09-08 01:16:34 -04:00
Joseph Doherty f1db90cb8a Merge branch 'worktree-agent-a5e1884475a5b785e' into feat/flow-debugger-script-entry 2026-09-08 01:16:11 -04:00
Joseph Doherty a5979b5cfd feat(management): FlowDebugRunner.RunScriptAsync — write-kind vs direct traced call by trigger kind (flow debugger script entry)
Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
2026-09-08 01:15:57 -04:00
Joseph Doherty 912e519954 fix(central-ui): ParameterValueForm — raise ValidChanged on schema set so required-field validity is never stale
Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
2026-09-08 01:15:40 -04:00
Joseph Doherty acf4ab3d4d Merge branch 'worktree-agent-ac243fcc404f04015' into feat/flow-debugger-script-entry 2026-09-08 01:15:04 -04:00
Joseph Doherty 5b185c93ff feat(central-ui): IFlowDebugService script entry — GetInstanceScripts / PredictScript / RunScript over the flattened configuration
Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
2026-09-08 01:14:40 -04:00
Joseph Doherty 067a858ce9 feat(cli): flow-debug run-script — run a site script by name through the flow debugger
Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
2026-09-08 01:13:15 -04:00
Joseph Doherty 001123d930 Merge branch 'worktree-agent-a5e1884475a5b785e' into feat/flow-debugger-script-entry 2026-09-08 01:11:04 -04:00
Joseph Doherty a437e0c14f Merge branch 'worktree-agent-a59908183c5526bc7' into feat/flow-debugger-script-entry 2026-09-08 01:09:34 -04:00
Joseph Doherty a36c813b89 feat(central-ui): ParameterValueForm.ValidChanged — additive validity callback
Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
2026-09-08 01:09:30 -04:00