Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
245 commits
Select commit Hold shift + click to select a range
a214719
FAT M1: remove duplicate late navigation parity owner
masarray Sep 9, 2026
c6a856e
FAT M0: lock engineering authority and navigation regression contract
masarray Sep 9, 2026
ee1b83b
FAT M0: freeze Engineering workstation architecture contract
masarray Sep 9, 2026
661f359
FAT M1: add guarded canonical-shell migration
masarray Sep 9, 2026
d56fdab
FAT M1: run guarded canonical-shell migration
masarray Sep 9, 2026
4fd3d6f
FAT M1: make seven-destination shell canonical
github-actions[bot] Sep 9, 2026
7085d3f
FAT M1: keep navigation ownership in canonical MainWindow
masarray Sep 9, 2026
1710c52
FAT M1: lock canonical seven-destination shell ownership
masarray Sep 9, 2026
f5d0458
ci: guarded M1 seven-slot consistency fix
masarray Sep 10, 2026
f2df6d0
ci: fix guarded M1 migration newline matching
masarray Sep 10, 2026
b3058ce
fix: complete canonical seven-slot navigation ownership
github-actions[bot] Sep 10, 2026
acf76cd
docs: lock canonical seven-slot FAT navigation invariant
masarray Sep 10, 2026
1a0d3db
test: lock seven-cell responsive navigation geometry
masarray Sep 10, 2026
954795a
test: bind MainWindow navigation clamp to canonical FAT index
masarray Sep 10, 2026
4850435
chore: stage guarded M2 permanent FAT host migration
masarray Sep 10, 2026
b648186
chore: run guarded M2 permanent FAT host migration
masarray Sep 10, 2026
2c1a2ac
chore: correct guarded M2 launcher occurrence check
masarray Sep 10, 2026
523d8ab
chore: rerun guarded M2 migration with precise launcher target
masarray Sep 10, 2026
b885965
feat: complete M2 permanent production FAT host
github-actions[bot] Sep 10, 2026
581e3b4
docs: record M2 permanent FAT host verification contract
masarray Sep 10, 2026
cc0f855
test: make M2 permanent-host regression line-ending stable
masarray Sep 10, 2026
2f82570
test: align P0 no-flicker contract with M2 background prewarm
masarray Sep 10, 2026
6f67d92
chore: stage guarded M3 capture target latch migration
masarray Sep 10, 2026
a921fc8
chore: run guarded M3 capture target latch migration
masarray Sep 10, 2026
3d6a019
feat: start M3 selected IED binding with capture target latch
github-actions[bot] Sep 10, 2026
9556d6a
test: lock M3 viewed IED and capture target separation
masarray Sep 10, 2026
398b00f
chore: stage guarded M3 deterministic viewed IED binding
masarray Sep 10, 2026
ea3cb29
chore: run guarded M3 deterministic viewed IED binding migration
masarray Sep 10, 2026
ae0f0f3
feat: make M3 Engineering IED view binding deterministic
github-actions[bot] Sep 10, 2026
dd1343a
test: lock final M3 Explorer-to-FAT binding contract
masarray Sep 10, 2026
effc8f9
M3: infer production IED plan type for selected-device binding
masarray Sep 10, 2026
ec4b65c
chore: stage M3 persistence ownership guard
masarray Sep 10, 2026
e216eae
chore: run guarded M3 persistence migration
masarray Sep 10, 2026
b52843a
M3: fail closed on per-IED persistence restore
github-actions[bot] Sep 10, 2026
10dcbbc
M3: lock fail-closed per-IED restore contract
masarray Sep 10, 2026
8d1eb7e
M5: add DeviceId-aware persisted IED ownership guard
masarray Sep 10, 2026
73435c8
chore: stage guarded M5 persistence authority migration
masarray Sep 10, 2026
0c3e13d
chore: run guarded M5 persistence authority migration
masarray Sep 10, 2026
a9d6dd1
M5: bind persisted FAT ownership to Engineering DeviceId
github-actions[bot] Sep 10, 2026
4751621
M5: lock DeviceId ownership and read-only reconciliation
masarray Sep 10, 2026
f6ae335
docs: record M3 closure and M5 persistence invariants
masarray Sep 10, 2026
348c5b8
docs: clarify M5 reconciliation is pre-session and non-producing
masarray Sep 10, 2026
2fe9188
docs: mark M3 code and CI gate complete
masarray Sep 10, 2026
178b68d
M4: add fail-closed production FAT capture target adapter
masarray Sep 10, 2026
9ba4be8
chore: stage guarded M4 production adapter wiring
masarray Sep 10, 2026
9dcc6db
chore: run guarded M4 production adapter wiring
masarray Sep 10, 2026
2e37628
M4: add production capture lease and continue isolation regressions
masarray Sep 10, 2026
59d1d10
M4: latch production FAT target across prepare and continue
github-actions[bot] Sep 10, 2026
7a1570b
FAT M6: lock embedded production report preview parity
masarray Sep 10, 2026
8c0d2aa
FAT M7: remove obsolete native side-panel report preview
masarray Sep 10, 2026
4d8d773
FAT M7: guard single production preview authority
masarray Sep 10, 2026
bd6c083
FAT M7: remove obsolete native preview history inspector
masarray Sep 10, 2026
df62112
FAT M7: guard removal of obsolete preview inspector stack
masarray Sep 10, 2026
e373118
FAT M7: align M3 latch regression with production controller adapter
masarray Sep 10, 2026
025447a
FAT M7: keep cleanup guard on the current preflight authority
masarray Sep 10, 2026
aa11604
M7 retire duplicate native FAT workspace authority
masarray Sep 10, 2026
b65ccf9
M7 mount production FAT directly in canonical XAML slot
masarray Sep 10, 2026
b5a3421
M7 remove obsolete native FAT export authority
masarray Sep 10, 2026
a3972d5
M7 update canonical FAT shell regression contract
masarray Sep 10, 2026
166a6f6
M7 lock single production FAT authority regression
masarray Sep 10, 2026
1044d6e
M7 remove retired native FAT explorer reconciler
masarray Sep 10, 2026
8baacf5
M7 remove retired native FAT persistence safety runtime
masarray Sep 10, 2026
5269fed
M7 guard retired native FAT runtime fragments
masarray Sep 10, 2026
352883c
M7 align M6 preview regression with canonical FAT tab authority
masarray Sep 10, 2026
bf0b93b
fix(FAT): stop background bootstrap from mutating Engineering acquisi…
masarray Sep 10, 2026
f563aed
fix(FAT): preserve Engineering static DataSet authority
masarray Sep 10, 2026
f3c9f30
fix(FAT): normalize hidden donor before WPF Show and fail visibly
masarray Sep 10, 2026
883ec4a
test(FAT): cover field regression for static authority and WPF donor …
masarray Sep 10, 2026
fac9588
perf(FAT): keep static authority reassertion passive
masarray Sep 10, 2026
9d2baeb
Keep embedded Static DataSet FAT off the legacy 250ms polling path
masarray Sep 10, 2026
9275a54
Add regression coverage for embedded FAT polling isolation
masarray Sep 10, 2026
87ab156
fix(fat): canonicalize Engineering workspace projection
masarray Sep 11, 2026
bb83b3e
fix(fat): render permanent loading shell before first FAT frame
masarray Sep 11, 2026
b305c0c
fix(fat): expose deterministic bootstrap state in permanent shell
masarray Sep 11, 2026
9129074
style(fat): compact production grid and widen IEC reference
masarray Sep 11, 2026
d40feb6
test(fat): lock compact grid density and wider IEC reference
masarray Sep 11, 2026
20f8880
perf(fat): reuse verified source descriptions in persistence
masarray Sep 11, 2026
b78dea8
perf(fat): carry verified source descriptions through bootstrap
masarray Sep 11, 2026
a08e3e7
perf(fat): expose canonical described SCL sources from projection
masarray Sep 11, 2026
f76826d
perf(fat): remove repeated SCL hashing from Engineering bootstrap
masarray Sep 11, 2026
2f9918b
test(fat): guard single-hash Engineering source pipeline
masarray Sep 11, 2026
3b49206
test(fat): align Engineering bootstrap contract with described sources
masarray Sep 11, 2026
e1c6a6e
fix(fat): canonicalize live aliases and speed staged reopen
masarray Sep 11, 2026
3999745
test(fat): keep strict duplicate guard coverage after alias self-heal
masarray Sep 11, 2026
221b2a2
fix(fat): self-heal proven static/manual live-reference shadows
masarray Sep 11, 2026
f901bb3
test(fat): cover restored manual alias shadow from field
masarray Sep 11, 2026
7341e60
FAT: add canonical legacy evidence migration
masarray Sep 11, 2026
7560f65
FAT: enforce canonical static rows before production host
masarray Sep 11, 2026
e8254db
FAT: regress canonical legacy row migration
masarray Sep 11, 2026
2cc9495
FAT: keep legacy selection cleanup as canonical guard
masarray Sep 11, 2026
f3657cd
Fix field FAT canonical authority normalization
masarray Sep 11, 2026
169c530
Add regression for Engineering authority field failure
masarray Sep 11, 2026
fd65abe
Keep Engineering FAT authority immutable during migration
masarray Sep 11, 2026
cefe09e
Recognize Engineering projection as static DataSet authority
masarray Sep 11, 2026
5ba59bd
Assert immutable Engineering DataSet authority field contract
masarray Sep 11, 2026
4a02d82
Fix required fields in Engineering authority regression fixture
masarray Sep 11, 2026
eac060b
FAT P1A: stop legacy bootstrap on Engineering tab entry
masarray Sep 11, 2026
f6ca0bf
Test P1A Engineering to FAT navigation boundary
masarray Sep 11, 2026
4f463bb
Add P1B sparse canonical FAT evidence overlay
masarray Sep 11, 2026
1a3ba25
Finish P1A native FAT grid and wire P1B evidence overlay
masarray Sep 11, 2026
52e8fce
Complete P1A direct Engineering FAT surface
masarray Sep 11, 2026
0258c09
Test P1B sparse evidence on canonical Engineering row keys
masarray Sep 11, 2026
7a3323b
Lock P1A direct rows and P1B overlay boundaries
masarray Sep 11, 2026
1da860a
Add sparse native FAT overlay state
masarray Sep 11, 2026
ea3117b
Preserve M6 FAT host authority contract
masarray Sep 11, 2026
9ade43b
Harden P1 canonical grid regression semantics
masarray Sep 11, 2026
76baae7
P1C align native FAT grid with Engineering visual authority
masarray Sep 11, 2026
467c498
Add P1C shared Engineering grid visual regression coverage
masarray Sep 11, 2026
22afb4b
Add P1D native FAT arm session state
masarray Sep 11, 2026
113eb45
Add P1D ARM-only native FAT coordinator
masarray Sep 11, 2026
4dca6aa
Make P1D sparse FAT evidence access thread-safe
masarray Sep 11, 2026
eb73dbc
Implement P1D ARM-only Engineering FAT start
masarray Sep 11, 2026
13f9230
Dispose P1D native FAT arm subscriptions on shutdown
masarray Sep 11, 2026
d90e426
Add P1D ARM-only FAT regression coverage
masarray Sep 11, 2026
ab45352
Fix P1D rolling evidence transition semantics
masarray Sep 11, 2026
2b88ce6
Add P2 native FAT evidence hydration state
masarray Sep 12, 2026
926d7a8
Add P2 snapshot and merge helpers for sparse evidence
masarray Sep 12, 2026
003b435
Add P2 async native FAT evidence hydration
masarray Sep 12, 2026
99c226d
Implement P2 async evidence hydration and shared rolling clock
masarray Sep 12, 2026
e1c96ad
Add P2 async evidence hydration regression coverage
masarray Sep 12, 2026
c363caf
Fix P2 rolling dots switch expression
masarray Sep 12, 2026
bb0bf77
Hydrate P2 from existing FAT snapshots without bootstrap
masarray Sep 12, 2026
495fde7
Test P2 passive legacy evidence hydration
masarray Sep 12, 2026
f877d9c
FAT P3: add immutable native preview snapshot
masarray Sep 12, 2026
124e54a
FAT P3: add lazy native print preview renderer
masarray Sep 12, 2026
680631a
FAT P3: wire lazy immutable preview capture
masarray Sep 12, 2026
f1c74c4
FAT P3: expose lazy selected-IED print preview
masarray Sep 12, 2026
723e986
FAT P3: add lazy immutable preview regressions
masarray Sep 12, 2026
c5e3ec0
FAT P4A: bind evidence by IEDName and IEC telegram
masarray Sep 12, 2026
28a55fb
FAT P4B: preserve timestamped structured evidence
masarray Sep 12, 2026
5ef1b9f
FAT P4C: add canonical seven-column contract
masarray Sep 12, 2026
1a1ae47
FAT P4C: apply seven-column Explorer view
masarray Sep 12, 2026
4515916
FAT P4C: lock canonical seven-column regression
masarray Sep 12, 2026
8d6045c
FAT P4C: fix evidence field namespace
masarray Sep 12, 2026
df7353e
FAT: remove duplicate P4C column application
masarray Sep 12, 2026
6dba347
FAT: make P4C columns canonical grid authority
masarray Sep 12, 2026
625b5b9
test: lock P4C single-authority column contract
masarray Sep 12, 2026
f3a8b13
FAT P4D: align immutable preview snapshot with P4C columns
masarray Sep 12, 2026
dde92be
FAT P4D: add immutable snapshot report layout adapter
masarray Sep 12, 2026
d4eb066
FAT P4D: render immutable preview through FixedDocument viewer
masarray Sep 12, 2026
ab249ba
test: keep P3 immutable snapshot contract under P4D
masarray Sep 12, 2026
6964efe
test: lock P4D FixedDocument preview contract
masarray Sep 12, 2026
6b5d4c9
test: align P1 visual contract with P4C Live Value authority
masarray Sep 12, 2026
9ebe0a9
FAT P4D: preserve timestamped evidence in report snapshot
masarray Sep 12, 2026
dcec536
FAT P4D: add layout-first native PDF serialization
masarray Sep 12, 2026
47df5d4
FAT P4D: save immutable layout through shared PDF service
masarray Sep 12, 2026
f4edbe0
FAT P4D: add Save PDF parity to FixedDocument preview
masarray Sep 12, 2026
8b814dd
test: align immutable preview with timestamped P4B evidence
masarray Sep 12, 2026
b13a89b
test: close P4D preview and PDF parity contract
masarray Sep 12, 2026
f9d248e
test: start P4E evidence isolation regression gauntlet
masarray Sep 12, 2026
220285c
FAT P4E: add exact command feedback correlation
masarray Sep 12, 2026
712575c
test: lock P4E command feedback identity correlation
masarray Sep 12, 2026
9ec392d
test: make P4D PDF source contract line-ending agnostic
masarray Sep 12, 2026
af9c572
test: align P1 sparse evidence contract with P4C column authority
masarray Sep 12, 2026
1a8d358
refactor: start P5 by isolating manual FAT compatibility host
masarray Sep 12, 2026
8fc44d8
refactor: remove dead automatic Engineering FAT bootstrap module
masarray Sep 12, 2026
e875d5e
test: lock P5 removal of automatic Engineering FAT bootstrap
masarray Sep 12, 2026
143fca9
refactor: remove legacy bootstrap state parameters from native FAT host
masarray Sep 12, 2026
8f1bf20
fix: require explicit control feedback reference for stable confirmation
masarray Sep 12, 2026
e8e92f1
test: lock explicit-only command feedback identity
masarray Sep 12, 2026
83d4976
test: lock P5 native FAT runtime against legacy bridge reentry
masarray Sep 12, 2026
3de255e
FAT P5: remove dead Engineering projection bridge
masarray Sep 12, 2026
7bfec6c
test: align Engineering FAT regression with P5 bridge removal
masarray Sep 12, 2026
3d59731
test: retire P0 bootstrap-only regressions after P5
masarray Sep 12, 2026
b1e4600
test: make M7 cleanup enforce P5 bootstrap retirement
masarray Sep 12, 2026
2619d2c
test: make permanent-host regression follow P5 native entry
masarray Sep 12, 2026
24cffc1
test: close P5 legacy bridge removal gate
masarray Sep 12, 2026
3375654
FAT P5: retire zero-reparse Engineering workspace adoption bridge
masarray Sep 12, 2026
2040ba9
test: lock retired Engineering workspace adoption bridge
masarray Sep 12, 2026
faad2ff
FAT P5: refresh canonical FAT after static authority update
masarray Sep 12, 2026
367db09
fix: preserve shared SCL workspace while removing bootstrap caller
masarray Sep 12, 2026
6ea69c7
test: make P4E feedback fallback guard comment-safe
masarray Sep 12, 2026
a6e97d5
fix: separate native FAT values from evidence timestamps
masarray Sep 12, 2026
26f040a
fix: split FAT values timestamps and complete result
masarray Sep 12, 2026
4c5765a
fix: snapshot exact FAT signal and timestamp columns
masarray Sep 12, 2026
34b0d32
fix(fat): align report with nine-column evidence grid
masarray Sep 12, 2026
1038e53
fix(fat): restore native report signoff page
masarray Sep 12, 2026
f905dfd
fix(fat): finalize native report with signoff
masarray Sep 12, 2026
d7801ad
fix(fat): restore professional native print preview
masarray Sep 12, 2026
bc86619
test(fat): lock professional preview and nine-column report
masarray Sep 12, 2026
3328509
fix(fat): refresh timestamp evidence with value cells
masarray Sep 12, 2026
4fe1fa4
fix(fat): refresh timestamp columns through evidence contract
masarray Sep 12, 2026
bd7ff38
test(fat): lock live timestamp refresh in nine-column grid
masarray Sep 12, 2026
c94e4c9
fix(fat): surface observation progress after evidence capture
masarray Sep 12, 2026
0288bd2
test(fat): lock one-of-two and two-of-two observation feedback
masarray Sep 12, 2026
dd2ecfa
fix(fat): restore print snapshot evidence namespace
masarray Sep 12, 2026
09dbcd9
fix(fat): unify preview timestamp contract
masarray Sep 12, 2026
dd793e6
fix(fat): disambiguate preview path types
masarray Sep 12, 2026
3fd2549
test(fat): lock stable identity against current key authority
masarray Sep 12, 2026
c07aee3
test(fat): align grid regression with nine-column contract
masarray Sep 12, 2026
d0f0e94
test(fat): assert structured timestamp columns separately
masarray Sep 12, 2026
cf4a63e
test(fat): keep evidence isolation with split timestamps
masarray Sep 12, 2026
27eee87
test(fat): assert immutable preview with split timestamps
masarray Sep 12, 2026
318c65b
test(fat): lock report preview to split timestamp evidence
masarray Sep 12, 2026
67c2d63
fix(control): default interlock and sync checks once per signal
masarray Sep 12, 2026
d49fa22
test(control): lock safe interlock and sync defaults
masarray Sep 12, 2026
e03c998
fix(fat): use shared operator signal names in report snapshots
masarray Sep 12, 2026
16e5c0e
feat(fat): add shared vector report branding
masarray Sep 12, 2026
1bdad19
fix(fat): clean customer report and map completed rows to OK
masarray Sep 12, 2026
65086f0
fix(fat): remove internal wording from sign-off report
masarray Sep 12, 2026
62c45e9
fix(fat): center preview controls and fit whole page
masarray Sep 12, 2026
0505208
test(fat): lock report cleanup and whole-page preview contract
masarray Sep 12, 2026
a15cba6
fix(fat): polish report preview presentation
masarray Sep 13, 2026
8669135
fix(fat): compile report logo image pipeline
masarray Sep 13, 2026
7021aa3
feat(fat): add native COMTRADE and time sync diagnostics
masarray Sep 13, 2026
a11fe41
test(fat): relax FileDirectory source guard
masarray Sep 13, 2026
2a60928
fix(fat): pin evidence to recycled rows and flush on shutdown
masarray Sep 13, 2026
b6dc2f6
test(fat): tighten recycled-row field guard
masarray Sep 13, 2026
9c407d9
fix(fat): bind evidence cells to canonical row identity
masarray Sep 13, 2026
0116c06
fix(fat): use DataContext-bound evidence columns
masarray Sep 13, 2026
0c50fbf
fix(fat): install bound evidence runtime and flush on close
masarray Sep 13, 2026
a0a4c4d
refactor(fat): remove row-recycle text patch
masarray Sep 13, 2026
0e12599
fix(report): fit logos adaptively in header slot
masarray Sep 13, 2026
201345a
test(fat): exercise real WPF row recycling and adaptive logos
masarray Sep 13, 2026
06d7b5e
test(fat): enable WPF recycling regression harness
masarray Sep 13, 2026
86b7a18
test(fat): expect DataContext-bound evidence columns
masarray Sep 13, 2026
fd246bc
test(fat): validate bound evidence refresh authority
masarray Sep 13, 2026
be32d1e
test(fat): import root ARSAS namespace for WPF harness
masarray Sep 13, 2026
6e5366e
fix(ci): expose internals to regression tests
masarray Sep 13, 2026
48e1710
fix(ci): restore test implicit IO namespace
masarray Sep 13, 2026
b678b14
fix(fat): freeze evidence before per-IED persistence
masarray Sep 13, 2026
601985d
fix(fat): persist capture before IED teardown
masarray Sep 13, 2026
f99790d
fix(fat): remove obsolete compatibility navigation button
masarray Sep 13, 2026
a7f428c
test(fat): cover teardown persistence and compatibility guard
masarray Sep 13, 2026
45789fc
fix(fat): keep persistence worker compile-safe
masarray Sep 13, 2026
4e10d81
fix(fat): import evidence session model for durability worker
masarray Sep 13, 2026
6b76648
perf(fat): reuse frozen IED identity and coalesce evidence writes
masarray Sep 13, 2026
4d42d18
perf(fat): freeze canonical IED identity once per runtime session
masarray Sep 13, 2026
36cfe1d
fix(fat): add IED-owned sparse evidence store
masarray Sep 13, 2026
f59cc25
refactor(fat): persist detached sparse evidence per IED
masarray Sep 13, 2026
083a93a
fix(fat): auto-load evidence by IEDName independent of FAT arm
masarray Sep 13, 2026
3203d2d
test(fat): cover IED-owned auto-load and continued capture
masarray Sep 13, 2026
3768ff5
perf(fat): load each IED evidence store once per runtime session
masarray Sep 13, 2026
0416a98
fix(fat): keep evidence snapshot valid after IED detach
masarray Sep 13, 2026
41bd8b1
fix(fat): persist capture even after rapid IED removal
masarray Sep 13, 2026
ba5c8e1
perf(fat): prepare evidence independently for every opened IED
masarray Sep 13, 2026
15c7692
fix(fat): defer SCL evidence load until IED identity is applied
masarray Sep 13, 2026
be0d867
fix(fat): remove obsolete workspace switcher
masarray Sep 13, 2026
e165ad2
feat(fat): include verified auxiliary evidence in reports
masarray Sep 13, 2026
7cded3e
FAT report: improve evidence table readability
masarray Sep 13, 2026
87888be
Tests: lock readable eight-column FAT report layout
masarray Sep 13, 2026
d51405a
Report: enlarge evidence text and compact table rows
masarray Sep 13, 2026
68d0daf
Report: harden customer wording and local timestamps
masarray Sep 13, 2026
08185c9
Tests: align report wording and local timestamp regressions
masarray Sep 13, 2026
e71712d
Merge PR #304: FAT canonical Engineering rows and evidence migration
masarray Sep 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 67 additions & 19 deletions IoListTestingWindow.EmbeddedEngineeringHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,21 @@ internal static void RegisterEmbeddedEngineeringFatHost()
handledEventsToo: true);
}

internal void PrepareForEmbeddedEngineeringHost()
{
// WPF refuses Window.Show() when ShowActivated=false while WindowState=Maximized.
// The production FAT XAML historically starts maximized, therefore normalize the
// invisible donor BEFORE Show(). Its exact center is re-parented into MainWindow on
// Loaded; the donor itself never needs a maximized native HWND.
WindowState = WindowState.Normal;
ShowActivated = false;
ShowInTaskbar = false;
Opacity = 0d;
WindowStartupLocation = WindowStartupLocation.Manual;
Left = -32000d;
Top = -32000d;
}

private static void EmbeddedEngineeringFatHost_Loaded(object sender, RoutedEventArgs e)
{
if (sender is not IoListTestingWindow window ||
Expand All @@ -45,9 +60,7 @@ window.Owner is not MainWindow owner ||
// MainWindow's legacy launcher still calls Show() on this Window. Make that bootstrap
// surface invisible immediately; the actual production visual is moved into Engineering
// on the next Loaded-priority dispatcher turn, before ContextIdle command-panel work.
window.ShowActivated = false;
window.ShowInTaskbar = false;
window.Opacity = 0d;
window.PrepareForEmbeddedEngineeringHost();

window.Dispatcher.BeginInvoke(
DispatcherPriority.Loaded,
Expand All @@ -64,24 +77,30 @@ private void TryMountIntoEngineering(MainWindow owner)
{
EnsureProductionFatPresentationForEmbeddedHost();
DisableLegacyEmbeddedCommandPanel();
var surface = DetachProductionFatCentralWorkspace();
if (surface == null)
return;
var surface = DetachProductionFatCentralWorkspace()
?? throw new InvalidOperationException("Production FAT center could not be detached from its donor window.");

_engineeringEmbeddedSurface = surface;
_engineeringEmbeddedMounted = owner.MountProductionFatWorkspace(this, surface);
if (!_engineeringEmbeddedMounted)
return;
throw new InvalidOperationException("Engineering FAT host rejected the production workspace surface.");

// The central FAT view now belongs to MainWindow. Keep this Window loaded and
// hidden because existing controller/session/event code is intentionally reused.
Hide();
}
catch (Exception ex)
{
// Never leave an invisible off-screen donor as a silent blank FAT failure.
// Restore the historical standalone presentation so the operator has a usable
// production FAT surface and a visible diagnostic if embedding itself fails.
WindowState = WindowState.Maximized;
Opacity = 1d;
ShowInTaskbar = true;
ShowActivated = true;
WindowStartupLocation = WindowStartupLocation.CenterOwner;
Left = double.NaN;
Top = double.NaN;
MessageBox.Show(
owner,
$"ARSAS could not embed the production FAT workspace. The standalone FAT window will remain available.\n\n{ex.Message}",
Expand Down Expand Up @@ -190,22 +209,51 @@ private void DisableLegacyEmbeddedCommandPanel()

internal void SelectEngineeringDeviceForEmbeddedFat(Iec61850MonitorDevice? device)
{
if (!_engineeringEmbeddedMounted || device == null)
if (!_engineeringEmbeddedMounted)
return;

var match = Project.Ieds.FirstOrDefault(ied =>
(!string.IsNullOrWhiteSpace(ied.LiveDeviceId) &&
ied.LiveDeviceId.Equals(device.DeviceId, StringComparison.OrdinalIgnoreCase)) ||
(!string.IsNullOrWhiteSpace(ied.IpAddress) &&
ied.IpAddress.Equals(device.IpAddress, StringComparison.OrdinalIgnoreCase)) ||
ied.IedName.Equals(device.SclIedName, StringComparison.OrdinalIgnoreCase) ||
ied.IedName.Equals(device.Name, StringComparison.OrdinalIgnoreCase));
if (match == null || ReferenceEquals(SelectedIed, match))
// M3 viewed-device contract: the persistent Engineering IED Explorer owns
// what the FAT grid displays. SelectedIed/Session.SelectContext changes only that
// projection; an active capture remains latched inside its per-IED controller.
// Clearing the Explorer selection or selecting an IED outside this FAT projection
// must clear the FAT view instead of silently leaving the previous IED on screen.
if (device == null)
{
if (CanSelectIed)
SelectedIed = null;
return;
}

// Resolve by strongest Engineering identity first. Do not use one OR predicate:
// a weak fallback on an earlier project row must never beat an exact live DeviceId.
var match = Project.Ieds.FirstOrDefault(_ => false);
if (!string.IsNullOrWhiteSpace(device.DeviceId))
{
match = Project.Ieds.FirstOrDefault(ied =>
!string.IsNullOrWhiteSpace(ied.LiveDeviceId) &&
ied.LiveDeviceId.Equals(device.DeviceId, StringComparison.OrdinalIgnoreCase));
}

if (match == null && !string.IsNullOrWhiteSpace(device.SclIedName))
{
match = Project.Ieds.FirstOrDefault(ied =>
ied.IedName.Equals(device.SclIedName, StringComparison.OrdinalIgnoreCase));
}

if (match == null && !string.IsNullOrWhiteSpace(device.Name))
{
match = Project.Ieds.FirstOrDefault(ied =>
ied.IedName.Equals(device.Name, StringComparison.OrdinalIgnoreCase));
}

if (match == null && !string.IsNullOrWhiteSpace(device.IpAddress))
{
match = Project.Ieds.FirstOrDefault(ied =>
!string.IsNullOrWhiteSpace(ied.IpAddress) &&
ied.IpAddress.Equals(device.IpAddress, StringComparison.OrdinalIgnoreCase));
}

// Do not retarget an active production FAT transaction/session. When idle, the
// persistent Engineering IED Explorer is the navigation/selection authority.
if (!CanSelectIed)
if (ReferenceEquals(SelectedIed, match) || !CanSelectIed)
return;

SelectedIed = match;
Expand Down
56 changes: 56 additions & 0 deletions IoListTestingWindow.ReleaseNavigationGuard.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Threading;

namespace ArIED61850Tester;

/// <summary>
/// Release guard for the obsolete compatibility navigation control. Native FAT now lives in
/// the Engineering workstation itself, so the old "Engineering" return button has no valid
/// user-facing purpose and can re-enter the compatibility mount/unmount path unexpectedly.
/// Keep the legacy host code available for explicit compatibility work, but remove its risky
/// navigation button from the shipped UI.
/// </summary>
public partial class IoListTestingWindow
{
private bool _releaseObsoleteEngineeringButtonHidden;

[ModuleInitializer]
internal static void RegisterIoListFatReleaseNavigationGuard()
{
EventManager.RegisterClassHandler(
typeof(IoListTestingWindow),
FrameworkElement.LoadedEvent,
new RoutedEventHandler(IoListFatReleaseNavigationGuard_Loaded),
handledEventsToo: true);
}

private static void IoListFatReleaseNavigationGuard_Loaded(object sender, RoutedEventArgs e)
{
if (sender is not IoListTestingWindow window || window._releaseObsoleteEngineeringButtonHidden)
return;

window._releaseObsoleteEngineeringButtonHidden = true;
window.Dispatcher.BeginInvoke(
new Action(() => HideObsoleteEngineeringNavigation(window)),
DispatcherPriority.Loaded);
}

private static void HideObsoleteEngineeringNavigation(DependencyObject root)
{
if (root is Button button &&
string.Equals(button.Content?.ToString()?.Trim(), "Engineering", StringComparison.OrdinalIgnoreCase))
{
button.IsEnabled = false;
button.Focusable = false;
button.Visibility = Visibility.Collapsed;
return;
}

var childCount = VisualTreeHelper.GetChildrenCount(root);
for (var index = 0; index < childCount; index++)
HideObsoleteEngineeringNavigation(VisualTreeHelper.GetChild(root, index));
}
}
Loading
Loading