Commit Graph

844 Commits

Author SHA1 Message Date
Joseph Doherty 2aede140e2 deploy(qa): b3021e7c to vq03/vq04 (55->57, artifacts deployed); SimpleAlarmStatusRequest copied from vd03; register row 126 closed 2026-09-28 11:12:05 -04:00
Joseph Doherty 5cc09b08ef deploy(vd03): b3021e7c — script file access live (AllowedRoots E:\ApiInstall\ScadaBridge\recipes); gate 31/31, rig 8/8
Second vd03 window of the day: no migrations, appsettings.Site.json gains ScriptFileAccess:AllowedRoots
(pushed over SMB before the swap), sample recipes in E:\ApiInstall\ScadaBridge\recipes. The Delmia
test receiver now reads + parses the downloaded file; real HTTP R100 -> 12 values loaded, R900 -> rejected
with line numbers. verify-mes-test-machine.sh: D1's cleared check reads through BTDB, so it only runs
with group C (the rig runs VERIFY_GROUPS=AD).
2026-09-28 10:45:54 -04:00
Joseph Doherty b3021e7c5f feat(scripts): read-only, allow-listed Files global for site scripts; Delmia test receiver parses recipe files
Script file access (design docs/plans/2026-09-28-script-file-access-design.md): Files.ReadTextAsync /
ReadLinesAsync / ExistsAsync on site ScriptGlobals (+ Instance.Files), backed by the site-singleton
ScriptFileReader. The one host-mediated exception to the System.IO ban - scripts still never name a
System.IO type. OFF by default: ScadaBridge:SiteRuntime:ScriptFileAccess:AllowedRoots (empty = every call
throws Disabled) + MaxFileBytes (1 MiB, validated 1..64 MiB, roots must be absolute). Guard: fully
qualified, no device paths / ADS, canonical path strictly inside a root (directory-boundary match), no
reparse point on the file or any directory below the root, size cap before and during the read.
Errors are one Commons type, ScriptFileAccessException(+ScriptFileAccessFailure); Commons.Types.Scripts
joins the default script imports on every surface so it binds by short name. Mirrored on
ScriptCompileSurface (CompileFiles, parity-pinned) and the Test Run sandbox (binds, refuses Disabled).
Inbound (central) scripts do not get it.

Rig: docker/recipes (sample RecipeValueName,RecipeValue files incl. an invalid one) bind-mounted
read-only at /app/recipes on both site-a nodes with AllowedRoots [/app/recipes]. The TestMesMachine
SimDelmiaRecipe simulator now reads + parses the downloaded file, converts each value to its recipe tag's
type and loads it all-or-nothing (14 new TestDelmiaReceiver attributes); verify-mes-test-machine.sh
group A covers accept / re-download / invalid lines / NotFound / OutsideAllowedRoots, VERIFY_GROUPS
selects groups (rig: AD).
2026-09-28 10:36:42 -04:00
Joseph Doherty 0af0672597 deploy(vd03): fe89363b + migrations 56/57; in-memory MES/Delmia/alarm-API test machines
vd03 (DEV) upgraded 2b9a7c3c -> fe89363b via the deployment-only winrm channel: COPY_ONLY backup,
55->57 delta script (AddAlarmMesReportable, AddSiteArtifactRevision), ~53 s window, snapshots
identical to baseline, artifacts deployed. Register row 126 now covers the QA pair only.

docker/seed-mes-test-machine.sh (idempotent) builds a standalone TestMesMachine base template -
Left/Right TestMESReceiver + TestDelmiaReceiver (prod attribute names, STATIC), computed alarms
with IsMesReportable, CvdReactor-compatible MesMoveIn/MesMoveOut/ProcessRecipeDownload/AlarmStatus
scripts ported to SetAsync+WaitAsync, and Galaxy-side simulators with reject/no-response knobs -
plus instances SBTEST01/02 and the SimpleAlarmStatusRequest (was a stub) / AlarmStatusRequest
inbound methods in the legacy /mes/(simple)alarmstatus shapes, resolving machines through BTDB.
BTDB rows SBTEST01=990001 / SBTEST02=990002 added on vd03.
docker/verify-mes-test-machine.sh drives the real inbound methods via flow-debug: PASS 25/25.
2026-09-28 10:10:17 -04:00
Joseph Doherty fad833e8d1 docs(former-api-specs): legacy MES alarm API — code-verified behaviour notes
Checked against the legacy mesapi source (MesNotifier/MesServices/Tag) plus ServiceStack/OrmLite
6.0.2 in a scratch harness:
- unhandled exceptions are an HTTP 500 ServiceStack ErrorResponse, not WasSuccessful=false
- no matching alarms = success with an empty list; failures don't short-circuit
- AckDT is null only for a null MXAccess value, not 'when unacked'
- tag type-conversion failures are silent (InAlarm false -> alarm drops out)
- simplealarmstatus SAPID edge cases: null never matches, "" matches, duplicates -> arbitrary TOP 1
- 'test' API keys hit the production BatchDB (TestDb routing never reaches MesNotifier)
- latent SetResult-after-timeout race in the MXAccess data-change callback
2026-09-28 09:25:10 -04:00
Joseph Doherty fb54ed428b docs(register): row 126 — TODO roll migrations 56/57 (AddAlarmMesReportable, AddSiteArtifactRevision) to vd03/vq03/vq04 with the 55→57 delta script
Claude-Session: https://claude.ai/code/session_01Y5ef34iUUMjmwnMpL9xgmB
2026-09-14 14:43:18 -04:00
Joseph Doherty ac833f5ace docs: pending-updates plan — all 12 tasks completed; rig gate 13/13 + Playwright 3/3 on the merged tip
Claude-Session: https://claude.ai/code/session_01Y5ef34iUUMjmwnMpL9xgmB
2026-09-14 14:38:32 -04:00
Joseph Doherty d8979664f1 docs: site artifact revision, pending-updates indicator, rail scroll pane
Claude-Session: https://claude.ai/code/session_01Y5ef34iUUMjmwnMpL9xgmB
2026-09-14 14:01:07 -04:00
Joseph Doherty 47e20dd8a8 docs(plans): pending-updates design + plan (site artifact staleness, rail indicator, scrollable nav)
Claude-Session: https://claude.ai/code/session_01Y5ef34iUUMjmwnMpL9xgmB
2026-09-14 13:28:49 -04:00
Joseph Doherty 18ebfe7194 docs(design): MES-reportable alarm flag — status merged + rig gate PASS
Claude-Session: https://claude.ai/code/session_01Y5ef34iUUMjmwnMpL9xgmB
2026-09-11 10:46:26 -04:00
Joseph Doherty 4cfa645bfb docs: MES-reportable alarm flag plan — all 16 tasks completed
Claude-Session: https://claude.ai/code/session_01Y5ef34iUUMjmwnMpL9xgmB
2026-09-11 10:46:05 -04:00
Joseph Doherty 6ac95ea888 fix(template-engine): carry IsMesReportable onto derived-template placeholder alarms and through descendant reconcile; final-review doc fixes
Claude-Session: https://claude.ai/code/session_01Y5ef34iUUMjmwnMpL9xgmB
2026-09-11 10:45:09 -04:00
Joseph Doherty 421d2d305e feat(docker): seed + verify scripts for the MES-reportable alarm demo — rig live gate PASS
Task 13/14. seed-mes-alarm-demo.sh builds a template whose three computed alarms differ in
how they acquire the flag (template --mes-reportable, nothing, instance override over a
template false), a site Call script projecting them through Alarms.CurrentAsync() /
MesReportableAsync(), and two inbound methods + a scoped API key. Idempotent by name lookup.

verify-mes-alarm-demo.sh drives the real inbound HTTP surface: PASS 14/14 on the docker rig
(migration 20260911135501_AddAlarmMesReportable applied at boot). Playwright
AlarmOverride_MesReportable_RoundTrips passed. Results + the facts the gate established are
in design doc section 8.

Claude-Session: https://claude.ai/code/session_01Y5ef34iUUMjmwnMpL9xgmB
2026-09-11 10:33:40 -04:00
Joseph Doherty ce8fc092c8 docs: MES-reportable alarm flag — component docs, CLAUDE.md, register rows 121–122
Claude-Session: https://claude.ai/code/session_01Y5ef34iUUMjmwnMpL9xgmB
2026-09-11 10:17:02 -04:00
Joseph Doherty 73f2a032e0 docs: MES-reportable alarm flag — design + 16-task implementation plan
Moves the legacy BTDB MachineAlarm.FlaggedForMES lookup onto TemplateAlarm.IsMesReportable
(instance-overridable), surfaces it as ScriptAlarm.IsMesReportable / Alarms.MesReportableAsync(),
and adds an AlarmStatus inbound method demo on the docker rig. Native alarms stay on the
severity band (no per-alarm row).

Claude-Session: https://claude.ai/code/session_01Y5ef34iUUMjmwnMpL9xgmB
2026-09-11 09:50:54 -04:00
Joseph Doherty 31b1b8db76 docs(#36): design doc §8/§10 — live-gate results and the String-node retarget
Claude-Session: https://claude.ai/code/session_01XPsuy2ZZ5Gbyfpt8PrK5BV
2026-09-10 15:54:11 -04:00
Joseph Doherty 29ca6b15ab docs(#36): rig live gate PASS (two runs, reset echo held 751 ms on run 2); seed retargeted to String nodes; register row 120 — OPC UA scalar writes go out as String variants
Claude-Session: https://claude.ai/code/session_01XPsuy2ZZ5Gbyfpt8PrK5BV
2026-09-10 15:53:51 -04:00
Joseph Doherty 17d5d3e639 fix(scripts): reset-aware handshake refuses a null reset value; document additive timeouts (#36 review)
A null resetValue encoded to null, which wrote an empty string and then handed the
waiter a null target (= any change), fast-pathing on the stale cache and reinstating
the race the overload exists to close. The context parameter is now non-nullable and
the accessor throws ArgumentException before any write. Also: additive-timeout note on
all surfaces, batch-failure message no longer names the bool overload, and the
error-message/batch-failure branches are pinned.

Claude-Session: https://claude.ai/code/session_01XPsuy2ZZ5Gbyfpt8PrK5BV
2026-09-10 15:35:50 -04:00
Joseph Doherty ae23c40a74 docs: reset-aware handshake — spec note, component doc, Delmia/Ipsen notes, register row 119, CLAUDE.md (#36)
Claude-Session: https://claude.ai/code/session_01XPsuy2ZZ5Gbyfpt8PrK5BV
2026-09-10 15:23:09 -04:00
Joseph Doherty e5c536c6b7 feat(commons): HandshakePhase + HandshakeResult for the reset-aware handshake (#36)
Claude-Session: https://claude.ai/code/session_01XPsuy2ZZ5Gbyfpt8PrK5BV
2026-09-10 15:18:10 -04:00
Joseph Doherty 9bb373c4a1 docs(scripts): implementation plan for #36 — reset-aware WriteBatchAndWaitAsync handshake
Claude-Session: https://claude.ai/code/session_01XPsuy2ZZ5Gbyfpt8PrK5BV
2026-09-10 15:15:27 -04:00
Joseph Doherty 0e6cef05e3 docs(scripts): design for #36 — reset-aware WriteBatchAndWaitAsync handshake
The MES/Delmia handshake fast-paths on the previous run's cached CompleteFlag
because the reset write has not echoed back before the wait registers. An
edge-triggered wait is rejected (a subscription can swallow the reset when the
device flips inside one sampling interval); the fix encodes the reset leg inside
a new WriteBatchAndWaitAsync overload that observes the reset echo before writing
the trigger and returns a phase-aware HandshakeResult.

Claude-Session: https://claude.ai/code/session_01XPsuy2ZZ5Gbyfpt8PrK5BV
2026-09-10 15:06:56 -04:00
Joseph Doherty b5eb08f1a9 fix(flow-debugger): method pane takes structured parameters via ParameterValueForm + raw-JSON escape hatch (#37)
The Run-inbound-API-method pane rendered one text box per top-level schema
field and coerced the text on the page; an array/object field went through
JsonNode.Parse and, on failure, was SENT AS A STRING, while an empty box was
silently dropped. A required array-of-object parameter (MesMoveOut WorkOrders)
could not be entered at all — QA runs reached the site with "WorkOrders":[].

- The method pane now renders the same shared ParameterValueForm the script
  pane uses (typed inputs, nested groups, add/remove list item editors,
  $ref:lib: resolution, inline validation), keyed on the method id so a change
  of method remounts it. The page keeps ONE value tree and BuildParameters()
  serializes it as-is; the flat _inputs / Coerce() / SetInput path is deleted.
- Form | Raw JSON toggle: raw mode is a Monaco json editor for the whole
  request body, given the method's root schema for completion, parsed and
  schema-validated (InboundApiSchema.Validate) on every edit with the error
  inline. Entering raw mode seeds the editor from the tree; leaving it
  re-mounts the form over the last valid tree.
- Run is disabled while the form or the raw document is invalid (a required
  field left empty disables Run before the first keystroke).
- localStorage per-method entry stores the value tree; on restore it is
  validated against the schema and dropped if invalid, which also retires the
  pre-#37 flat string-per-field entries.
- ParameterValueForm.ToJsonSchema / JsonElementToObject made internal static
  for page reuse.
- Tests: 7 new bUnit tests (WorkOrders array-of-object round-trip to the
  RunMethodAsync payload, required list-item gating, invalid raw JSON blocks
  Run + shows parse/schema/non-object errors, valid raw JSON sent verbatim and
  survives the switch back to the form, method switch resets, persisted tree
  restored, legacy flat entry dropped); existing method-pane tests moved to
  the form's #param-<field> ids and fill the required field before Run.
  Playwright smoke selector moved to #param-Text.
- Docs: design doc, Component-CentralUI.md entry-points bullet, CLAUDE.md.

CentralUI.Tests 1425/1425 green; Playwright project builds.

Claude-Session: https://claude.ai/code/session_01XPsuy2ZZ5Gbyfpt8PrK5BV
2026-09-10 14:54:21 -04:00
Joseph Doherty 3b1211d79f docs(flow-debugger): design for #37 — method pane structured parameters
Claude-Session: https://claude.ai/code/session_01XPsuy2ZZ5Gbyfpt8PrK5BV
2026-09-10 14:49:12 -04:00
Joseph Doherty 17864d1ae4 docs(deploy): records for 2b9a7c3c on DEV vd03 and the QA pair vq03/vq04
Both driven from the Mac over the winrm CLI (WinRM 5985 + SMB 445, no helper
on the boxes). Migration 53->55; the first Central boot encrypts
DataConnections.PrimaryConfiguration (dp:protocol:v1:), so rollback is the
COPY_ONLY DB restore, not a binary swap. QA: all four nodes stopped together,
one shared-DB migration, 2 min 35 s window, preflight against a restored clone.

Claude-Session: https://claude.ai/code/session_01RgthVLVU5CJ8SUuEwruTkt
2026-09-10 12:25:53 -04:00
Joseph Doherty 2b9a7c3ca0 Synchronize CLI documentation with management command parity 2026-09-10 01:20:12 -04:00
Joseph Doherty 0cc9db9e94 Record completed CLI parity verification and deployment 2026-09-10 00:54:52 -04:00
Joseph Doherty 2750bd2809 Complete management API and CLI command parity 2026-09-10 00:51:45 -04:00
Joseph Doherty 477e2abe97 Document management API and CLI parity gaps 2026-09-10 00:31:23 -04:00
Joseph Doherty 9ee402bbcd Resolve all 46 low-severity architecture review findings 2026-09-09 22:56:36 -04:00
Joseph Doherty 9a87d7a328 Resolve all 33 medium-severity architecture review findings
Second slice of the 2026-09-09 whole-system review remediation
(docs/plans/2026-09-09-arch-review.md §10), on top of the High slice 146a1323.

Runtime/devices: SR-2 alarm on-trigger integration scope; SR-3 correlated NativeAlarmActor
subscribe retry; SR-4 immutable audited DB target; SR-5 ordered InstanceActor stop/flush;
SR-12 rehydration fence; SR-13 S&F gate recheck per delivery; DC-4 no OPC UA security
downgrade; DC-5 alarm snapshot for every new subscriber; ORCH-1 sync-dispose joins the pump.

Management/UI: MG-2 site scope on audit tree + Flow Debugger Replay; MG-3 stale-probe memo
removed; MG-4 server-owned bulk-deploy deadline; UI-5 sandbox runs in a killable child
process (new CentralUI.SandboxWorker project); UI-14 bounded sandbox output/IPC.

Edge/audit: EI-1 relay audit ownership; EI-2 SkipBodyCapture suppresses error text; EI-3/EI-11
error-field redaction + caps; EI-4 single relay deadline, pre-execution-only retry; EI-5
authenticated relay provenance; EI-10 body cap before audit read.

Persistence/contracts: DL-1 global Instance.UniqueName unique index + conflict translation;
DL-2 DataConnection protocol config encrypted at rest (migration
20260909203046_EnforceGlobalInstanceNamesAndProtectProtocolConfiguration — coordinated
central upgrade, old binaries cannot read protected rows); DL-3 bounded Replay paging;
DL-6 cross-site Overwrite of a deployed instance rejected; XC-4 proto descriptor contract test.

Config/hygiene: XC-1 central listener isolation by local port; XC-2/XC-3 inert SMTP + cron
keys removed from rig settings; CM-2 env2 bootstrap guard enabled; DC-6 deploy site exit code;
DC-7 notifier retries only explicit standby rejection; XC-5 ClusterClient purged from docs.

Gates recorded in the report: build 0/0, 9 397 passed / 0 failed, rig redeployed on all
eight nodes with the migration applied. 46 Low findings remain open.
2026-09-09 22:05:30 -04:00
Joseph Doherty 146a13238f Resolve all high-severity architecture review findings 2026-09-09 16:13:58 -04:00
Joseph Doherty 8bfe65512e docs: update architecture review with independent findings and verification 2026-09-09 15:06:28 -04:00
Joseph Doherty c078bc8fd4 docs: whole-system architectural/code review 2026-09-09 (83 findings, 8 High; 9-WP remediation program)
Eight parallel area reviewers + orchestrator verification at main @ d8229916.
All 12 CLAUDE.md design commitments hold. Highs: DC-1 no unsubscribe ever sent,
DC-2 redundant Mx handle release freezes live tag, DC-3 device writes stashed
across reconnect, SR-1 sync Attributes[] blocks script pool, CM-1 no gRPC
message-size limit, MG-1 trust deny-list gap (CompilerServices/Loader), UI-1 UI
config edits bypass IAuditService, UI-2 session ping defeats idle timeout.
Suite: build 0/0, 9231 passed / 1 failed (ORCH-1 OperationTrackingStore
sync-dispose race). No code changed by this review.
2026-09-09 14:44:26 -04:00
Joseph Doherty 97f01ae98e fix(flow-debugger): final-review remediation — 2000-row trace pull, shared ExceptionHeader parser, surrogate-safe clip, wording, alarm source, register renumber (I1/I2/M1-M8) 2026-09-09 13:30:48 -04:00
Joseph Doherty 0bacc3630e chore(plans): flow-debugger step logs — all 15 tasks complete, gate evidence 2026-09-09 13:03:37 -04:00
Joseph Doherty 82739ec912 docs+rig(flow-debugger): step logs v1.4 specs, register rows, FlowLogDemo seed + verification step J 2026-09-09 12:56:39 -04:00
Joseph Doherty 99330453ab docs(plans): Flow Debugger step logs + exceptions — design, mockup, 15-task plan (v1.4) 2026-09-09 11:21:52 -04:00
Joseph Doherty c27b22ead3 chore(plans): instance picker — all tasks complete, gate evidence
Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
2026-09-08 10:04:45 -04:00
Joseph Doherty b19da25d32 docs(plans): instance picker design — keyboard activation via TreeView selection, tab-out does not close, explicit handlers, loading gate
Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
2026-09-08 09:56:07 -04:00
Joseph Doherty a071433096 docs: instance picker on Flow Debugger + Debug View
Note the shared InstancePicker combobox (2026-09-08 design) replacing
the flat instance <select> on both pages, in Component-CentralUI.md's
Flow Debugger and Debug View sections and the CLAUDE.md Flow Debugger
bullet.

Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
2026-09-08 09:43:04 -04:00
Joseph Doherty 1c665d3acb chore(plans): instance picker tasks 2-3 complete
Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
2026-09-08 09:40:12 -04:00
Joseph Doherty 8f8100c7a8 docs(plans): instance picker — node shape + orphan rules as shipped; task 1 complete
Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
2026-09-08 09:26:41 -04:00
Joseph Doherty 356b7620f8 docs(plans): Instance Picker implementation plan (8 tasks)
Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
2026-09-08 09:18:02 -04:00
Joseph Doherty 861f510427 docs(plans): Instance Picker design — area-tree combobox for Flow Debugger + Debug View instance selection
Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
2026-09-08 09:15:57 -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 999882f6c1 chore(plans): flow debugger script entry — task ledger complete + gate evidence (rig H/H2/I, Playwright 4/4, browser)
Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
2026-09-08 01:47:49 -04:00
Joseph Doherty 061f2b722b docs: run-script help names the server ceiling; Open in Debug View applies to script entries
Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
2026-09-08 01:39:46 -04:00
Joseph Doherty 4bb831fc41 docs: flow debugger script entry — component specs, CLAUDE.md, design pointers
Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
2026-09-08 01:21:43 -04:00
Joseph Doherty fefa3ffa77 docs(plans): flow debugger script entry — implementation plan (13 tasks, 6 waves)
Claude-Session: https://claude.ai/code/session_01NcMG6xXdsJbmD2wYAgkK29
2026-09-08 01:02:10 -04:00