Skip to content

Releases: Cwgtshome/ProtectionAI-Releases

ProtectionAI v1.10.0

Choose a tag to compare

@Cwgtshome Cwgtshome released this 03 Aug 21:05

102 registered [WorkspaceView] modules (adds the Ed.2 Test Mode & Sim Flag module), 30 AI
copilot tools, 4 AI providers, 7 UI languages, 3,195 tests (3,079 at v1.9.0 — this release
adds 116). Ribbon: 17 tabs, 85 groups, 146 controls.

The release theme is instrument reach without dishonesty: more shapes, more instruments, more
standard surfaces — every new capability stating exactly what it is and refusing what it cannot
attest.

Added

  • Seven selectable test-set shapes for the simulator (TestSetProfiles), from a 3V/3I field
    set to a 12V/12I laboratory set, with a 6×64 A high-current variant and a 6V/9I three-winding
    shape between. Each profile states what the shape cannot do — no polarizing voltage on the
    three-phase set, one current triplet cannot drive both windings of a differential — because the
    point of rehearsing on the set you will carry to site is meeting its limits at the desk rather
    than at the substation. The shape is enforced, not decorative: an injection over the profile's
    range refuses. A Shape selector in Home → Hardware (visible only for simulator-type drivers)
    persists the choice, and changing shape re-arms the isolation gate exactly as a hardware swap
    would — a different shape is a different instrument.

  • Five rehearsal instrument classes in the test-set selector: CMC-class, F6-class, SMRT-class,
    DRTS-class and Mentor-class — the full qualified simulator wearing a per-vendor-class identity,
    so a demonstration or dry run can be staged around any vendor family an operator owns, with no
    hardware on the desk. The honesty is structural and test-pinned: every identity names itself
    simulated, the vendor's name appears only inside wording that denies being the product ("not a
    Doble product; no vendor protocol"), the Vendor field is always GridAPM, the isolation gate keys
    on the runtime type so a rehearsal set always receives the simulator acknowledgement, and the
    real vendor stubs stay stubs, out of the selector.

  • Full SCPI instrumentation on the generic SCPI driver, every addition template-gated —
    a capability exists exactly when its command templates are configured, and unconfigured
    operations keep refusing with the missing capability named. Measurement inputs return the
    instrument's magnitude only (angle, frequency and derived powers are NaN: a sequential query
    is not a coherent acquisition window and must not dress up as one). Polled binary sensing raises
    real contact events while never advertising device timestamps — the event states host-poll
    provenance, and pulse-ramp/pickup-dropout still refuse, now citing that exact gap. Trigger
    arming is manual-release only. An error-queue drain (SYST:ERR?) runs after every command
    batch, default ON, aborting with the SCPI error named verbatim — silent command rejection is how
    a wrong injection happens. Aux DC and operator-declared per-channel frequency complete the set.

  • The OMICRON CM Engine adapter extended strictly against a graded public-attestation table
    (docs/research/CMENGINE-COMMANDS.md): trip timing from the device's own event buffer —
    DeviceRelativeTimestampedBinaryInputs is now genuinely advertised, with its claim stated
    exactly (device-relative ordering and intervals: yes; disciplined absolute UTC: no) — plus
    binary outputs, aux DC, a time-driven sequencer (deliberately not claiming SegmentRamp:
    held states are not interpolated segments), and enumerate-then-choose amplifier
    routing/paralleling with no hardcoded configuration numbers. Commands whose public attestation
    is incomplete — binary-triggered sequencer advance above all — are explicitly not built; a wrong
    guess there mis-times a protection test. HIL qualification remains pending and every new surface
    says so.

  • The Ed.2 Test Mode & Sim Flag module (IEC 61850 tab) — the vendor-neutral relay-side test
    surface. Publishes simulation-flagged GOOSE with both wire forms of the marker set together
    (a frame carrying only one is reported INCONSISTENT, never resolved by preference), monitors
    received GOOSE for the simulation marker and the 13-bit quality test bit (absent quality reports
    "none", never "clear"), and stages a duplicated-control-block switchover check that records what
    was published and captured. It does not command the IED's mode — that is an MMS write this
    application does not yet have — and it says so on its intro card; on the built-in simulator the
    switchover verdict is NOT VERIFIABLE with the reason spelled out. Transport provenance is on an
    always-visible line.

  • docs/research/ — the evidence base for every driver-scope decision this release makes:
    VENDOR-PROTOCOLS.md (Doble, Megger, ISA/Altanova and EuroSMC verdicts: no public wire
    protocol exists for any of them; per-vendor routes to the real interface documentation, with
    document part numbers where they exist), CMENGINE-COMMANDS.md (the graded CM Engine
    attestation table), and STANDARD-SURFACES.md (no universal test-set control standard exists;
    the vendor-neutral strategy runs through relay-side Ed.2 testing features, interchange files and
    SCPI instruments, with five prioritized gaps — an IEC 61850-8-1 MMS/ACSI client first).

Fixes

  • A pulse-ramp test asserted a premise the machine can disprove. It went red under load in two
    independent runs; the product was correct — a process-wide stall holding a 60 ms pulse energized
    past a competing stage's 1.5 s operate time makes that stage operate, exactly as a real relay
    behaves against a real test set whose controlling PC stalled. The test now measures each pulse's
    actual energized span from its own run and asserts the quiet-competing-stage claim only when the
    run stayed under the operate time; the pickup value and rest behaviour remain unconditional.
    This is the second test-side defect in the repo's history (after the breaker-failure separation
    floor), against many product defects — the doctrine of assuming the product wrong first stands,
    with the distinguishing question recorded in docs/TESTING.md.

  • The OMICRON adapter's phasor and event-buffer commands moved to their attested forms
    (out:v(1:n):… rather than the unattested out:ana:v(…) prefix; inp:buf:sam(bin,1) rather
    than sam(bin,on)) — the previous forms appear nowhere in the public record.

Testing

116 tests cover the new behaviour: shape catalog and enforcement, the rehearsal honesty contract,
SCPI instrumentation (deterministic via an injectable poll clock), the OMICRON extension
(attested command strings asserted literally, event-buffer parsing to the microsecond), and the
Ed.2 protocol and switchover mathematics. The localization ratchet moved 1,906 → 1,934, fully
attributed to the new module's mandated house-idiom literals.


Installer

ProtectionAI-Setup.msi is a Windows Installer (MSI) package. It installs ProtectionAI in Program Files, creates a Start Menu shortcut, registers Apps & Features uninstall support, and supports in-place major upgrades. ProtectionAI.App.exe is the same application as a self-contained single-file executable, for people who cannot run an installer.

This release is not Authenticode code signed. Windows SmartScreen will warn you when you run it, and that warning is expected. The checks below prove integrity (the bytes are the bytes we built) and source binding (the signed manifest came from this repository, tag and commit). They are not a Windows trust decision and do not stop SmartScreen warning.

Artifact digests (SHA-256)

7070803dc4f391bafb4ee409f878a2efc5914ae91509f07b6b6740452ed91bd8  protectionai-1.10.0-cyclonedx.json
e91dc38d48c4ead4d3735945db9ed3674625f954f47278f17226046193abce60  protectionai-1.10.0-cyclonedx.json.sha256
de239f78a5145bfb17384cc16a3480966856a4c168453720acec567d6573124e  ProtectionAI-Setup.msi
9cbe3c71301bcb27ef973440ae1b061154d2034e247d32ac77f10924a4b0e6ec  ProtectionAI.App.exe

Published alongside the artifacts as SHA256SUMS, with a detached Sigstore signature (SHA256SUMS.sig), the ephemeral signing certificate (SHA256SUMS.pem) and a self-contained bundle (SHA256SUMS.cosign.bundle). The software bill of materials (protectionai-1.10.0-cyclonedx.json) and its checksum sidecar (protectionai-1.10.0-cyclonedx.json.sha256) are both attached and covered by the signed manifest.

1. Verify integrity — the files are what we built

PowerShell:

foreach ($line in Get-Content .\SHA256SUMS) {
  $expected, $name = $line -split '\s+', 2
  $actual = (Get-FileHash $name.Trim() -Algorithm SHA256).Hash.ToLower()
  "{0}  {1}" -f $(if ($actual -eq $expected) { "OK  " } else { "FAILED" }), $name.Trim()
}

POSIX shell:

sha256sum -c SHA256SUMS

2. Verify authenticity — the digest list itself is genuine

Step 1 only proves the files match the list. This proves the list was produced by this release workflow. Install cosign and run:

cosign verify-blob SHA256SUMS \
  --signature SHA256SUMS.sig \
  --certificate SHA256SUMS.pem \
  --certificate-identity https://github.com/Cwgtshome/ProtectionAI/.github/workflows/release.yml@refs/tags/v1.10.0 \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  --certificate-github-workflow-repository Cwgtshome/ProtectionAI \
  --certificate-github-workflow-ref refs/tags/v1.10.0 \
  --certificate-github-workflow-sha d2f6c61b31de5e8dc9681fa03160dbb245aa0e82

Or with the bundle, which needs no separate certificate:

cosign verify-blob SHA256SUMS \
  --bundle SHA256SUMS.cosign.bundle \
  --certificate-identity https://github.com/Cwgtshome/ProtectionAI/.github/workflows/release.yml@refs/tags/v1.10.0 \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  --certificate-github-workflow-repository Cwgtshome/ProtectionAI \
  --certificate-github-workflow-ref refs/ta...
Read more

ProtectionAI v1.9.0

Choose a tag to compare

@Cwgtshome Cwgtshome released this 03 Aug 16:34

101 registered [WorkspaceView] modules, 30 AI copilot tools, 4 AI providers, 7 UI languages,
3,079 tests (3,056 at v1.8.1 — this release adds 23). Ribbon: 17 tabs, 85 groups, 144 controls.
No module or tool count moves.

Added

  • The search box now behaves like a Windows search box: it offers something before you type.
    Focusing it opened nothing at all, which meant the operator had to already know what the box could
    find. It now opens on two sections.

    Recent is the operator's own search history — persisted in its own file, most recent first,
    each row carrying what that search led to last time ("diff → Suggestion: Differential 87") so a
    remembered query is recognisable rather than a bare string. History is recorded on activation,
    never per keystroke
    : a history fed by keystrokes fills with the prefixes of one real search
    ("d", "di", "dis") and is worthless. Repeats increment a count rather than duplicating, ranking is
    frequency weighted with a fortnight half-life so an old commissioning job stops outranking today's
    work, and any row can be forgotten from where it is seen — otherwise the only way to remove a typo
    is to delete the whole history. Queries only: no results, no measurements, no relay data, because
    a search history accumulating test outcomes would be a second unmanaged copy of records that
    belong in the database.

    Suggested is what the session makes worth doing next, and every row states its basis
    "3 of 12 result(s) in this session failed", "51P Feeder Prot (Demo) is selected but nothing has
    been measured yet", "No test set connected". A suggestion with no stated reason is
    indistinguishable from a guess, and this product is used by people who have to justify what they
    did. NOT VERIFIABLE results are surfaced too, worded as could not be verified and never as a
    failure — it is the outcome most easily missed, because the run happened and the verdict did not.

  • Completions while typing, ranked with the same protection shorthand as the results. Typing
    diff offers Differential 87, Differential Characteristic Studio, Motor Differential 87M
    before the full result list, shortest first. These are completions rather than results — they
    finish the phrase instead of jumping to an answer, which is what makes a long module name
    reachable in three keystrokes. Fuzzy subsequence hits are deliberately excluded here: ovc is a
    legitimate result for Overcurrent but a nonsensical completion of those keystrokes.

  • Matched characters are emphasised in every row. Only a literal, contiguous match is bolded;
    a fuzzy hit still ranks but is drawn plain, because bolding scattered letters inside a word
    produces a ransom note. The shorthand table applies, so searching o/c emphasises Overcurrent.

  • Agentic AI suggestions, advisory and optional. When an API key is configured, the shell asks
    once per session — not per keystroke — for a few short searches worth running given the
    session state, and shows them under an explicitly advisory heading. The call is a one-shot
    provider request, deliberately not the copilot agent
    : TestingAgent.SendAsync appends to the
    conversation the user can see, so asking it would drop the prompt and its reply into their
    transcript, and it carries the whole tool set including the ones gated on confirmed_isolated.
    Suggestions need no tools and leave no trace in the chat. With no key there is no AI section at
    all, and any failure or timeout is logged and dropped — a search box that stalls because a model
    is slow would be a far worse feature than one that never shows an AI row.

  • Nothing offered from the search box can energize anything. Suggested rows open views, focus
    panels, connect the test set or pre-fill a query. Starting an injection is never one keystroke
    away from a text box; that path still runs through Tst.ReadyAsync and the isolation gate like
    every other run, and a test asserts it.

Fixed

  • The drop-down opened and vanished within a single click. The popup is StaysOpen="False", so
    opening it on the mouse-down that focuses the box left the matching mouse-up landing outside
    it and dismissing it immediately — indistinguishable from the feature not working. Opening is now
    deferred to Input priority, after the whole click has been delivered. Clicking a box that already
    holds a query re-opens its results rather than sitting inert.

  • Two suggested rows described a module instead of saying why they were being offered. The
    section's whole rule is that every row states its basis, and the two default starting points —
    Overcurrent 50/51 and Manual Injection — carried a feature blurb ("IDMT pickup and curve timing")
    in the place where every other row names the state that produced it. A description sitting where a
    reason belongs reads as a deduction without being one, which is worse than no subtitle. Both now
    say plainly that they are common starting points and that nothing in the session suggested them,
    so an operator can tell a default from an inference at a glance. Found by driving the published
    build, not by reading the code; a test now sweeps every session state and rejects any suggested row
    whose subtitle cites neither a count nor a condition.

  • A breaker-failure timing test was asserting the opposite of the property it guarded. It put a
    floor under the separation between the retrip and backup stages. But both stages are referred to
    the trip instant, so when the host delays the retrip the backup correctly stays at its own 2.0 s
    deadline and the separation shrinks — the floor fired precisely when the product was behaving as
    designed, and it failed the v1.9.0 release run at retrip 1.57 s, backup 2.00 s, separation 430 ms,
    all three of which are correct. The regression actually worth guarding is a backup timed from the
    retrip contact, so the test now proves that directly and deterministically: it runs the scenario
    twice with retrip settings 800 ms apart and asserts the backup does not move. Verified by mutation
    — chaining the backup off the retrip makes the backup shift by 799.4 ms and the test fail. No bound
    was widened; the old assertion was replaced because it was wrong, not because it was tight.

Testing

23 tests cover the new behaviour. SearchHistory and SearchSuggestions are BCL-only and compiled
directly into the test project alongside SearchRanker, so the suite exercises the code the shell
runs rather than a copy; SearchHistory takes its directory as a parameter precisely so the tests
point it at a temporary folder and never read or write the operator's own history.


Installer

ProtectionAI-Setup.msi is a Windows Installer (MSI) package. It installs ProtectionAI in Program Files, creates a Start Menu shortcut, registers Apps & Features uninstall support, and supports in-place major upgrades. ProtectionAI.App.exe is the same application as a self-contained single-file executable, for people who cannot run an installer.

This release is not Authenticode code signed. Windows SmartScreen will warn you when you run it, and that warning is expected. The checks below prove integrity (the bytes are the bytes we built) and source binding (the signed manifest came from this repository, tag and commit). They are not a Windows trust decision and do not stop SmartScreen warning.

Artifact digests (SHA-256)

295c263399ecf52a802b65bc01ced40cfc79dd057026ceff641983d3cec1f3fd  protectionai-1.9.0-cyclonedx.json
b8ef9e84aacd54411e5b3dd14ebf88503d45c4487477c40f2751e6ee73bbb811  protectionai-1.9.0-cyclonedx.json.sha256
dbbbf7b6811467566164eb217f96aad55319b794020d808509e0e006498635ba  ProtectionAI-Setup.msi
49da071528fbe3ac97b483092ca7567aef339a5b6e851a94a7af41942c07c5ef  ProtectionAI.App.exe

Published alongside the artifacts as SHA256SUMS, with a detached Sigstore signature (SHA256SUMS.sig), the ephemeral signing certificate (SHA256SUMS.pem) and a self-contained bundle (SHA256SUMS.cosign.bundle). The software bill of materials (protectionai-1.9.0-cyclonedx.json) and its checksum sidecar (protectionai-1.9.0-cyclonedx.json.sha256) are both attached and covered by the signed manifest.

1. Verify integrity — the files are what we built

PowerShell:

foreach ($line in Get-Content .\SHA256SUMS) {
  $expected, $name = $line -split '\s+', 2
  $actual = (Get-FileHash $name.Trim() -Algorithm SHA256).Hash.ToLower()
  "{0}  {1}" -f $(if ($actual -eq $expected) { "OK  " } else { "FAILED" }), $name.Trim()
}

POSIX shell:

sha256sum -c SHA256SUMS

2. Verify authenticity — the digest list itself is genuine

Step 1 only proves the files match the list. This proves the list was produced by this release workflow. Install cosign and run:

cosign verify-blob SHA256SUMS \
  --signature SHA256SUMS.sig \
  --certificate SHA256SUMS.pem \
  --certificate-identity https://github.com/Cwgtshome/ProtectionAI/.github/workflows/release.yml@refs/tags/v1.9.0 \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  --certificate-github-workflow-repository Cwgtshome/ProtectionAI \
  --certificate-github-workflow-ref refs/tags/v1.9.0 \
  --certificate-github-workflow-sha 0616546e08661fa2ee448870ff0a022faba94351

Or with the bundle, which needs no separate certificate:

cosign verify-blob SHA256SUMS \
  --bundle SHA256SUMS.cosign.bundle \
  --certificate-identity https://github.com/Cwgtshome/ProtectionAI/.github/workflows/release.yml@refs/tags/v1.9.0 \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  --certificate-github-workflow-repository Cwgtshome/ProtectionAI \
  --certificate-github-workflow-ref refs/tags/v1.9.0 \
  --certificate-github-workflow-sha 0616546e08661fa2ee448870ff0a022faba94351

Pin all five certificate constraints e...

Read more

ProtectionAI v1.8.1

Choose a tag to compare

@Cwgtshome Cwgtshome released this 03 Aug 14:12

101 registered [WorkspaceView] modules, 30 AI copilot tools, 4 AI providers, 7 UI languages,
3,056 tests. Ribbon: 17 tabs, 85 groups, 144 controls. No counts move.

Fixed

  • The centred search box was crowding both the window edge and the ribbon tabs, and the
    measurement showed why.
    It looked tight, and it was worse than tight: the stock caption is about
    25 DIP tall and the box was 30, so the box overhung the tab row by 7.5 DIP — it was not merely
    close to the tabs, it was overlapping them — while clearing the top of the window by only 3 DIP.

    The window now sets TitleBarHeight="36" and the box is 24 high, vertically centred in it. Measured
    after the change: 9 DIP of air above the box and 6 DIP below it to the tab strip, with no
    overlap anywhere. Outlook's caption is likewise taller than the Windows default, for the same
    reason — a search field needs a band of its own, not the leftovers of a caption sized for text.

    The horizontal margin is also symmetric now (14 DIP each side) so the box is not visually pulled
    toward the quick-access side or the window buttons, and the interior padding grew slightly so the
    watermark is not against the border. The two numbers are coupled: shrink TitleBarHeight without
    shrinking the box and the overlap returns, which is noted where both are set.


Installer

ProtectionAI-Setup.msi is a Windows Installer (MSI) package. It installs ProtectionAI in Program Files, creates a Start Menu shortcut, registers Apps & Features uninstall support, and supports in-place major upgrades. ProtectionAI.App.exe is the same application as a self-contained single-file executable, for people who cannot run an installer.

This release is not Authenticode code signed. Windows SmartScreen will warn you when you run it, and that warning is expected. The checks below prove integrity (the bytes are the bytes we built) and source binding (the signed manifest came from this repository, tag and commit). They are not a Windows trust decision and do not stop SmartScreen warning.

Artifact digests (SHA-256)

9ab576c93d7863a20a025a830c32ba8c4a10e783da45ca31b24ad24e4a3ac31e  protectionai-1.8.1-cyclonedx.json
1fed76640c9c1ee1d7a7bf026ade2a9e014ccf37f81e2748b11f3dedfca115a7  protectionai-1.8.1-cyclonedx.json.sha256
68b82568d68007c7ffac0534f03d1772f3718e3b43f676eaa49f9f2af00a09ef  ProtectionAI-Setup.msi
8a970e1a131c146b036032b478cc5d0eefec1df6e17e6a47fc440abdc2a2ea34  ProtectionAI.App.exe

Published alongside the artifacts as SHA256SUMS, with a detached Sigstore signature (SHA256SUMS.sig), the ephemeral signing certificate (SHA256SUMS.pem) and a self-contained bundle (SHA256SUMS.cosign.bundle). The software bill of materials (protectionai-1.8.1-cyclonedx.json) and its checksum sidecar (protectionai-1.8.1-cyclonedx.json.sha256) are both attached and covered by the signed manifest.

1. Verify integrity — the files are what we built

PowerShell:

foreach ($line in Get-Content .\SHA256SUMS) {
  $expected, $name = $line -split '\s+', 2
  $actual = (Get-FileHash $name.Trim() -Algorithm SHA256).Hash.ToLower()
  "{0}  {1}" -f $(if ($actual -eq $expected) { "OK  " } else { "FAILED" }), $name.Trim()
}

POSIX shell:

sha256sum -c SHA256SUMS

2. Verify authenticity — the digest list itself is genuine

Step 1 only proves the files match the list. This proves the list was produced by this release workflow. Install cosign and run:

cosign verify-blob SHA256SUMS \
  --signature SHA256SUMS.sig \
  --certificate SHA256SUMS.pem \
  --certificate-identity https://github.com/Cwgtshome/ProtectionAI/.github/workflows/release.yml@refs/tags/v1.8.1 \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  --certificate-github-workflow-repository Cwgtshome/ProtectionAI \
  --certificate-github-workflow-ref refs/tags/v1.8.1 \
  --certificate-github-workflow-sha 4988e6c2516e1345c4b6142afc89c47410c84ac8

Or with the bundle, which needs no separate certificate:

cosign verify-blob SHA256SUMS \
  --bundle SHA256SUMS.cosign.bundle \
  --certificate-identity https://github.com/Cwgtshome/ProtectionAI/.github/workflows/release.yml@refs/tags/v1.8.1 \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  --certificate-github-workflow-repository Cwgtshome/ProtectionAI \
  --certificate-github-workflow-ref refs/tags/v1.8.1 \
  --certificate-github-workflow-sha 4988e6c2516e1345c4b6142afc89c47410c84ac8

Pin all five certificate constraints exactly as shown: identity, issuer, repository, ref and SHA. Together they reject a signature from another workflow, repository, tag or commit. There is no long-lived private key: the certificate above was issued to this workflow's OIDC identity, is valid for minutes, and the signing event is recorded in the public Rekor transparency log.

3. Build provenance — not available for this release

No GitHub-hosted SLSA build-provenance attestation was recorded, so gh attestation verify will not find one. GitHub's attestation store is not offered to user-owned private repositories on this plan, and the source repository is private.

What still holds: the signed SHA256SUMS manifest binds every shipped content file by digest, and the Sigstore certificate in step 2 binds that manifest to this repository, tag ref and exact source SHA against a public transparency log. What is missing is GitHub's separate SLSA predicate and attestation-store record; no SLSA level is claimed.

Built from Cwgtshome/ProtectionAI@4988e6c. See docs/RELEASE-INTEGRITY.md for what each file is and why it exists.

ProtectionAI v1.8.0

Choose a tag to compare

@Cwgtshome Cwgtshome released this 03 Aug 13:42

101 registered [WorkspaceView] modules, 30 AI copilot tools, 4 AI providers, 7 UI languages,
3,056 tests. Ribbon: 17 tabs, 85 groups, 144 controls. No module, tool or test count moves — the
minor version reflects a change to where the operator's most-used control lives and a type ramp that
now governs the whole front end.

Changed

  • Search moved to the centre of the title bar, where Outlook puts it. It sat at the right end of
    the ribbon tab row, competing with seventeen tabs for the same strip.

    A note in the XAML had claimed true title-bar centring was impractical and would mean fighting the
    window-drag hit test. That was wrong, but only just: RibbonTitleBar is a HeaderedItemsControl
    whose Header is positioned by HeaderAlignment, and Center is one of the values it supports, so
    the search box simply becomes the header the window title used to occupy. Two things in the stock
    control had to be undone first, and finding them is the work:

    • the style applies a HeaderTemplate that renders the header as text, so assigning a
      UIElement printed its type name — the running app showed a title bar reading
      ProtectionAI.App.Views.RibbonSearchHost, and because the host never entered the visual tree the
      search box disappeared from the automation tree entirely;
    • PART_HeaderHolder is IsHitTestVisible="False", which is correct for a caption you drag the
      window by and fatal for a text box.

    Both are corrected at runtime. The cost is that this strip of the caption no longer drags the
    window, which is exactly how Outlook behaves around its own search box; the rest of the caption
    still drags. Every failure path leaves the box where it used to be, at the right end of the tab
    row, and says so in the log — a search box that silently vanished would be worse than one that is
    merely not centred.

    Because the box no longer shares a row with the tabs, the ribbon fit engine no longer shrinks it to
    buy the tab strip width — that step bought nothing once they stopped competing. It is now sized
    against the window, and the whole tab row is available to tabs, so fewer are ever parked into the
    overflow menu.

    Verified on the running app: centred, correctly themed (#252526 on dark), ShellSearchBox
    findable in the automation tree, click-to-focus working, typing dist opening the results popup.

  • Every font size in the front end is now a named step on one ramp. An audit found 356
    hard-coded sizes across 217 files in twenty distinct values
    — 9, 9.5, 10, 10.5, 11, 11.5, 12,
    12.5, 13, 13.5, 14, 15, 16, 17, 18, 20, 22, 24, 26 and 28 — where the house idiom describes about
    five. Half-steps that differ by half a pixel are not a design decision; they are drift, and their
    existence means the next contributor picks a number rather than a meaning. Fifty-four were below
    11 px
    , which on a field laptop in sunlight is where text stops being readable and starts being
    decoration.

    Ui.Size now names the ramp — Micro 11, Body 12, Strong 13, Subtitle 14, Title 16,
    SectionHeader 18, Page 22, Display 24, Hero 28 — and 280 call sites across 83 files were
    converted. Near-duplicates were snapped to the step they were already pretending to be and
    everything below 11 was raised: 9/9.5/10/10.5/11.5 → 11, 12.5 → 12, 13.5 → 13, 15 → 14, 17 → 16,
    20 → 22, 26 → 24. Sizes already on a step kept their value and gained a name. The intent was to
    remove invisible variation and raise unreadable text, not to resize the product.

    Chart text is deliberately not on this ramp: OxyPlot renders through its own pipeline and
    ChartTheme.cs remains its single source of truth. Ten OxyPlot annotation sizes were identified
    and left alone rather than converted by pattern-matching on the property name.


Installer

ProtectionAI-Setup.msi is a Windows Installer (MSI) package. It installs ProtectionAI in Program Files, creates a Start Menu shortcut, registers Apps & Features uninstall support, and supports in-place major upgrades. ProtectionAI.App.exe is the same application as a self-contained single-file executable, for people who cannot run an installer.

This release is not Authenticode code signed. Windows SmartScreen will warn you when you run it, and that warning is expected. The checks below prove integrity (the bytes are the bytes we built) and source binding (the signed manifest came from this repository, tag and commit). They are not a Windows trust decision and do not stop SmartScreen warning.

Artifact digests (SHA-256)

0939d9d5c1e6bcc6f83c652f70869544a2a4fcf6139acaa949f35d341b616c08  protectionai-1.8.0-cyclonedx.json
dfdc44708ed73388f1029f06dbab0411db35b42613d7586510ecd86d28fa5d90  protectionai-1.8.0-cyclonedx.json.sha256
b571ec50562c436a3f9b9181db8c2708a42e13c66b4331e9a744bc60bc561ebf  ProtectionAI-Setup.msi
1188ee0caa22d0af4b6670889768c3d15cc250c4cea54b376b147bef3f464602  ProtectionAI.App.exe

Published alongside the artifacts as SHA256SUMS, with a detached Sigstore signature (SHA256SUMS.sig), the ephemeral signing certificate (SHA256SUMS.pem) and a self-contained bundle (SHA256SUMS.cosign.bundle). The software bill of materials (protectionai-1.8.0-cyclonedx.json) and its checksum sidecar (protectionai-1.8.0-cyclonedx.json.sha256) are both attached and covered by the signed manifest.

1. Verify integrity — the files are what we built

PowerShell:

foreach ($line in Get-Content .\SHA256SUMS) {
  $expected, $name = $line -split '\s+', 2
  $actual = (Get-FileHash $name.Trim() -Algorithm SHA256).Hash.ToLower()
  "{0}  {1}" -f $(if ($actual -eq $expected) { "OK  " } else { "FAILED" }), $name.Trim()
}

POSIX shell:

sha256sum -c SHA256SUMS

2. Verify authenticity — the digest list itself is genuine

Step 1 only proves the files match the list. This proves the list was produced by this release workflow. Install cosign and run:

cosign verify-blob SHA256SUMS \
  --signature SHA256SUMS.sig \
  --certificate SHA256SUMS.pem \
  --certificate-identity https://github.com/Cwgtshome/ProtectionAI/.github/workflows/release.yml@refs/tags/v1.8.0 \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  --certificate-github-workflow-repository Cwgtshome/ProtectionAI \
  --certificate-github-workflow-ref refs/tags/v1.8.0 \
  --certificate-github-workflow-sha 1f8ca994a45dd8ed1997d68ac36aacdc62b05e2c

Or with the bundle, which needs no separate certificate:

cosign verify-blob SHA256SUMS \
  --bundle SHA256SUMS.cosign.bundle \
  --certificate-identity https://github.com/Cwgtshome/ProtectionAI/.github/workflows/release.yml@refs/tags/v1.8.0 \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  --certificate-github-workflow-repository Cwgtshome/ProtectionAI \
  --certificate-github-workflow-ref refs/tags/v1.8.0 \
  --certificate-github-workflow-sha 1f8ca994a45dd8ed1997d68ac36aacdc62b05e2c

Pin all five certificate constraints exactly as shown: identity, issuer, repository, ref and SHA. Together they reject a signature from another workflow, repository, tag or commit. There is no long-lived private key: the certificate above was issued to this workflow's OIDC identity, is valid for minutes, and the signing event is recorded in the public Rekor transparency log.

3. Build provenance — not available for this release

No GitHub-hosted SLSA build-provenance attestation was recorded, so gh attestation verify will not find one. GitHub's attestation store is not offered to user-owned private repositories on this plan, and the source repository is private.

What still holds: the signed SHA256SUMS manifest binds every shipped content file by digest, and the Sigstore certificate in step 2 binds that manifest to this repository, tag ref and exact source SHA against a public transparency log. What is missing is GitHub's separate SLSA predicate and attestation-store record; no SLSA level is claimed.

Built from Cwgtshome/ProtectionAI@1f8ca99. See docs/RELEASE-INTEGRITY.md for what each file is and why it exists.

ProtectionAI v1.7.3

Choose a tag to compare

@Cwgtshome Cwgtshome released this 03 Aug 12:57

101 registered [WorkspaceView] modules, 30 AI copilot tools, 4 AI providers, 7 UI languages,
3,056 tests. Ribbon: 17 tabs, 85 groups, 144 controls. No counts move.

Changed

  • "Are the outputs live, and how do I drop them" now sits at the centre of the status bar. Both
    the ■ STOP (F12) control and the output-state chip were at the far left of a strip that also
    carries the relay name, the test-set state, the licence and the clock — the most consequential
    thing the shell can tell an operator, competing with the least. They are now a single cluster
    pinned to the true horizontal centre of the window, which is where the eye goes and where a
    glance lands when someone is holding test leads.

    The status bar is now one item holding a three-column grid rather than a row of docked items.
    That is the substance of the change: a DockPanel, which is the StatusBar's default items
    panel, can dock left or right but cannot centre against the window, so the safety cluster could
    not have been placed there by alignment alone. The outer columns are equal-width stars and the
    middle is Auto, so the cluster stays centred at any width regardless of how much text either
    side happens to hold. Verified in the running app: the pair straddles the window centre to within
    2 px at 5146 px wide.

    The output-state chip is also larger — 12.5 px caption against the 11 px of the surrounding status
    text, with more padding and a taller minimum. Matching the licence state and the clock would have
    set the words that answer "can I touch the wiring" at the size of the words that answer "what time
    is it". The four renderings, their glyph shapes and the rule that colour never carries the state
    alone are unchanged.

Added

  • scripts\check-theme.ps1 — audits both semantic palettes without launching anything: every
    x:Key in one theme must exist in the other (the dictionaries are swapped wholesale at runtime,
    so a key present in only one resolves to nothing after a theme switch, silently and in one theme
    only), and 88 foreground/background pairs are checked against the floor their role requires —
    4.5:1 for text and for any caption on a filled chip or button in every state, 3:1 for structural
    lines, focus rings and the ribbon category accents. The contrast claims in the theme files'
    comments were verified once, by hand, and every later edit was on trust; they are now asserted.

  • scripts\check-theme-runtime.ps1 — the half a static audit cannot reach. It drives the
    published binary, switches Light then Dark, and samples rendered pixels against the declared
    palette. A correct palette on disk and the wrong colours on screen is exactly the shape of the
    AvalonDock tab-strip defect fixed in v1.7.0, where every resource mapping applied and the tabs
    stayed light in dark mode. It also asserts that the emergency-stop field is safety yellow
    #FFD100 in both themes and identically so, because that theme-invariance is a claim about
    safety chrome and nothing else was checking it. A blank capture is reported as INCONCLUSIVE
    rather than as a failure, so a sleeping monitor can never be mistaken for a theming defect.


Installer

ProtectionAI-Setup.msi is a Windows Installer (MSI) package. It installs ProtectionAI in Program Files, creates a Start Menu shortcut, registers Apps & Features uninstall support, and supports in-place major upgrades. ProtectionAI.App.exe is the same application as a self-contained single-file executable, for people who cannot run an installer.

This release is not Authenticode code signed. Windows SmartScreen will warn you when you run it, and that warning is expected. The checks below prove integrity (the bytes are the bytes we built) and source binding (the signed manifest came from this repository, tag and commit). They are not a Windows trust decision and do not stop SmartScreen warning.

Artifact digests (SHA-256)

105c51c9f4b5f6f1af69e5054b7377b2ec3e3a64b72174e2273afbf46156ec00  protectionai-1.7.3-cyclonedx.json
543929834be1b3576cc63ffe44766dbac9da455da54055087e10ec4bca4131b4  protectionai-1.7.3-cyclonedx.json.sha256
89008b1fd7865dc82413feb2b54e905af928557ed64c23c1bfd87e70edc23c04  ProtectionAI-Setup.msi
bf6f6c9bd6213f8e729f96f29629a647f94d42bd51a2a9d7e663c6aba94fa9e4  ProtectionAI.App.exe

Published alongside the artifacts as SHA256SUMS, with a detached Sigstore signature (SHA256SUMS.sig), the ephemeral signing certificate (SHA256SUMS.pem) and a self-contained bundle (SHA256SUMS.cosign.bundle). The software bill of materials (protectionai-1.7.3-cyclonedx.json) and its checksum sidecar (protectionai-1.7.3-cyclonedx.json.sha256) are both attached and covered by the signed manifest.

1. Verify integrity — the files are what we built

PowerShell:

foreach ($line in Get-Content .\SHA256SUMS) {
  $expected, $name = $line -split '\s+', 2
  $actual = (Get-FileHash $name.Trim() -Algorithm SHA256).Hash.ToLower()
  "{0}  {1}" -f $(if ($actual -eq $expected) { "OK  " } else { "FAILED" }), $name.Trim()
}

POSIX shell:

sha256sum -c SHA256SUMS

2. Verify authenticity — the digest list itself is genuine

Step 1 only proves the files match the list. This proves the list was produced by this release workflow. Install cosign and run:

cosign verify-blob SHA256SUMS \
  --signature SHA256SUMS.sig \
  --certificate SHA256SUMS.pem \
  --certificate-identity https://github.com/Cwgtshome/ProtectionAI/.github/workflows/release.yml@refs/tags/v1.7.3 \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  --certificate-github-workflow-repository Cwgtshome/ProtectionAI \
  --certificate-github-workflow-ref refs/tags/v1.7.3 \
  --certificate-github-workflow-sha adca8c4936acac67074e38781928178320ac0b9c

Or with the bundle, which needs no separate certificate:

cosign verify-blob SHA256SUMS \
  --bundle SHA256SUMS.cosign.bundle \
  --certificate-identity https://github.com/Cwgtshome/ProtectionAI/.github/workflows/release.yml@refs/tags/v1.7.3 \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  --certificate-github-workflow-repository Cwgtshome/ProtectionAI \
  --certificate-github-workflow-ref refs/tags/v1.7.3 \
  --certificate-github-workflow-sha adca8c4936acac67074e38781928178320ac0b9c

Pin all five certificate constraints exactly as shown: identity, issuer, repository, ref and SHA. Together they reject a signature from another workflow, repository, tag or commit. There is no long-lived private key: the certificate above was issued to this workflow's OIDC identity, is valid for minutes, and the signing event is recorded in the public Rekor transparency log.

3. Build provenance — not available for this release

No GitHub-hosted SLSA build-provenance attestation was recorded, so gh attestation verify will not find one. GitHub's attestation store is not offered to user-owned private repositories on this plan, and the source repository is private.

What still holds: the signed SHA256SUMS manifest binds every shipped content file by digest, and the Sigstore certificate in step 2 binds that manifest to this repository, tag ref and exact source SHA against a public transparency log. What is missing is GitHub's separate SLSA predicate and attestation-store record; no SLSA level is claimed.

Built from Cwgtshome/ProtectionAI@adca8c4. See docs/RELEASE-INTEGRITY.md for what each file is and why it exists.

ProtectionAI v1.7.2

Choose a tag to compare

@Cwgtshome Cwgtshome released this 03 Aug 08:47

101 registered [WorkspaceView] modules, 30 AI copilot tools, 4 AI providers, 7 UI languages,
3,056 tests. Ribbon: 17 tabs, 85 groups, 144 controls. No counts move.

The repository now has no known intermittent tests, and not one of them turned out to be a test
problem.
Chasing the last two documented flakes found four genuine defects — three in the
closed-loop engine, each of which would misreport a protection test on a machine that is merely
busy. That is the reason this release exists, and the reason the "it's just timing" instinct is now
written down as the wrong instinct.

Fixed

  • The closed-loop engine could return before its own deadline. DelayUntilAsync computed the
    time remaining against DateTime.UtcNow — the clock every measurement in the result is reported
    against — but slept on the runtime's monotonic timer. Those are different time bases and they
    drift, so a wait could end before the measuring clock agreed the interval had passed. The
    observable result was a breaker interrupting time shorter than the breaker's own mechanical
    opening time
    : 37.63 ms against a modelled 40 ms, a physically impossible figure in a protection
    report, produced with nothing wrong in the model. The wait now re-checks against the measuring
    clock and tops itself up. The deadline is unchanged — it no longer returns early.

  • A reclose command could be seen and then thrown away, and reported as a lockout.
    closeWaiter.Arm() ran after the arc-extinction wait, the open-breaker outputs and the 52a/52b
    feedback. A relay with a short dead time issues its close command inside that window, where the
    waiter was not yet armed; the edge was dropped, the wait timed out, and the run recorded "no
    reclose command within timeout"
    and declared lockout for a relay that had actually reclosed.
    On a high-speed autoreclose scheme this is a false verdict on the exact behaviour under test.
    ContactWaiter now records every rising edge whether armed or not, and Arm(sinceUtc) counts
    anything at or after the instant the sequence became interested — for a reclose, the trip that
    caused it.

  • A trip could be observed and still reported as no-trip. ContactWaiter.WaitAsync raced the
    contact against the timeout, and when the host had been descheduled both came due together and
    the race was a coin toss. Losing it returned "the relay did not assert binary input N" while the
    object was holding that input's trip timestamp — a verdict contradicting the measurement in hand.
    The contact task is now re-checked before any negative result is returned. The timeout still
    expires exactly when asked; it no longer discards evidence already collected. The timer is also
    cancelled once the race is settled rather than left running.

  • Modelled breaker instants were stamped with software latency. openAtMs = Now() recorded the
    moment the code finished two IO round trips, not the modelled arc-extinction instant the engine
    had just computed. Every interval derived from it inherited the scheduling jitter, and because a
    late open instant shortens the open-to-close interval, a stall produced an autoreclose dead
    time of 104.4 ms against the relay's own 120 ms setting
    . Breaker open and close instants are
    now the model's own; relay contact times remain genuine measurements taken from the driver's
    timestamps. The distinction is the point: measured quantities stay measured, modelled quantities
    are reported at the instant the model gives them.

  • The signal-clock slip test could not be right under load, for arithmetic reasons. Two
    channels at 50.0 and 50.2 Hz slip at 72 deg/s, so consecutive observations more than
    180 / 72 = 2.5 s apart are aliased — past half a turn, an advance is indistinguishable from a
    small step backwards, and no unwrapping can recover it. A stall that long made the relative angle
    appear to run in reverse with the simulator behaving perfectly. It also read its timestamp after
    ReadMeasurementsAsync returned rather than at the instant the angles were evaluated inside it.
    Channel phase is analytic (base + 360·f·t), so the fix is to choose the instants:
    SimulatorDriver.SignalClockSecondsOverride (internal, null in production, unreachable outside
    the test assembly) lets the test evaluate the rotation at exact t. The assertion moved from a
    ±15 % band to exact — 72.000000 deg/s, and every step exact to nine decimals — because the
    band was only ever absorbing host jitter.

Verified

20 consecutive runs of the three affected test classes green with a dotnet publish and two
CPU-saturating jobs running alongside, individual runs stretching from 2 s to 12 s under the load.
Before the fixes the same loop failed 1–2 times in every 8–15 runs. Full suite 3,056 / 0 failed on
an idle machine.


Installer

ProtectionAI-Setup.msi is a Windows Installer (MSI) package. It installs ProtectionAI in Program Files, creates a Start Menu shortcut, registers Apps & Features uninstall support, and supports in-place major upgrades. ProtectionAI.App.exe is the same application as a self-contained single-file executable, for people who cannot run an installer.

This release is not Authenticode code signed. Windows SmartScreen will warn you when you run it, and that warning is expected. The checks below prove integrity (the bytes are the bytes we built) and source binding (the signed manifest came from this repository, tag and commit). They are not a Windows trust decision and do not stop SmartScreen warning.

Artifact digests (SHA-256)

4fe30cd8aaf032538ffc9fc76f1bca1dcaeaae85a8b153ec3102f3086dd64326  protectionai-1.7.2-cyclonedx.json
aaf30ee4fbb0a14021c858915c69bf28d5b9e917cfbe9d09783c50039e171e69  protectionai-1.7.2-cyclonedx.json.sha256
803fd26621426ec789deefbe096e4ff7b965b9d78b5acb1e975ad95fd4b51b84  ProtectionAI-Setup.msi
32f9247f29f051707a0a0109b4c11bbdd7ec963e704a2c33d776a9eebe06a1a0  ProtectionAI.App.exe

Published alongside the artifacts as SHA256SUMS, with a detached Sigstore signature (SHA256SUMS.sig), the ephemeral signing certificate (SHA256SUMS.pem) and a self-contained bundle (SHA256SUMS.cosign.bundle). The software bill of materials (protectionai-1.7.2-cyclonedx.json) and its checksum sidecar (protectionai-1.7.2-cyclonedx.json.sha256) are both attached and covered by the signed manifest.

1. Verify integrity — the files are what we built

PowerShell:

foreach ($line in Get-Content .\SHA256SUMS) {
  $expected, $name = $line -split '\s+', 2
  $actual = (Get-FileHash $name.Trim() -Algorithm SHA256).Hash.ToLower()
  "{0}  {1}" -f $(if ($actual -eq $expected) { "OK  " } else { "FAILED" }), $name.Trim()
}

POSIX shell:

sha256sum -c SHA256SUMS

2. Verify authenticity — the digest list itself is genuine

Step 1 only proves the files match the list. This proves the list was produced by this release workflow. Install cosign and run:

cosign verify-blob SHA256SUMS \
  --signature SHA256SUMS.sig \
  --certificate SHA256SUMS.pem \
  --certificate-identity https://github.com/Cwgtshome/ProtectionAI/.github/workflows/release.yml@refs/tags/v1.7.2 \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  --certificate-github-workflow-repository Cwgtshome/ProtectionAI \
  --certificate-github-workflow-ref refs/tags/v1.7.2 \
  --certificate-github-workflow-sha 442426b55951b9087beeafce6e01da695d4278a5

Or with the bundle, which needs no separate certificate:

cosign verify-blob SHA256SUMS \
  --bundle SHA256SUMS.cosign.bundle \
  --certificate-identity https://github.com/Cwgtshome/ProtectionAI/.github/workflows/release.yml@refs/tags/v1.7.2 \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  --certificate-github-workflow-repository Cwgtshome/ProtectionAI \
  --certificate-github-workflow-ref refs/tags/v1.7.2 \
  --certificate-github-workflow-sha 442426b55951b9087beeafce6e01da695d4278a5

Pin all five certificate constraints exactly as shown: identity, issuer, repository, ref and SHA. Together they reject a signature from another workflow, repository, tag or commit. There is no long-lived private key: the certificate above was issued to this workflow's OIDC identity, is valid for minutes, and the signing event is recorded in the public Rekor transparency log.

3. Build provenance — not available for this release

No GitHub-hosted SLSA build-provenance attestation was recorded, so gh attestation verify will not find one. GitHub's attestation store is not offered to user-owned private repositories on this plan, and the source repository is private.

What still holds: the signed SHA256SUMS manifest binds every shipped content file by digest, and the Sigstore certificate in step 2 binds that manifest to this repository, tag ref and exact source SHA against a public transparency log. What is missing is GitHub's separate SLSA predicate and attestation-store record; no SLSA level is claimed.

Built from Cwgtshome/ProtectionAI@442426b. See docs/RELEASE-INTEGRITY.md for what each file is and why it exists.

ProtectionAI v1.7.1

Choose a tag to compare

@Cwgtshome Cwgtshome released this 03 Aug 07:12

101 registered [WorkspaceView] modules, 30 AI copilot tools, 4 AI providers, 7 UI languages,
3,056 tests (3,055 at v1.7.0 — this release adds one). Ribbon: 17 tabs, 85 groups, 144 controls.
No module or tool count moves. One intermittent test is repaired at root cause, and the repair
carries a second latent instance of the same defect with it.

Fixed

  • A driver test could fail without anything being wrong with the driver.
    AuxDcProfileTests.Playback_ReportsTheProfileValueForTheInstantItWasApplied went red during the
    v1.7.0 release qualification while a background job was competing for this two-core machine, and
    passed both in isolation and on an idle machine.

    The driver was never at fault and could not be: PlayAuxDcProfileAsync reads the elapsed time
    once per iteration and derives the demanded voltage, the segment index and the reported
    ElapsedSeconds from that one value, so the per-point assertions cannot race. Establishing that
    first is what stopped the investigation hunting a race that does not exist.

    The fragile claim was Assert.Contains(reports, r => r.AppliedVolts == 0.0) — "the interruption
    was really played". Profile playback waits on absolute deadlines, which is the correct
    production behaviour: a stalled host resynchronizes to real time rather than drifting, and the
    elapsed time it reports stays honest. The consequence is that which instants get sampled is the
    host scheduler's choice, so a stall spanning the profile's 300 ms zero segment leaves every
    catch-up sample past it and nothing reports 0 V. The assertion was a statement about the
    scheduler, not about the product.

    The repair is neither a widened tolerance nor a deleted assertion — that playback genuinely
    drives the interruption still has to be verified. Aux-DC playback gained an internal clock seam
    (IAuxDcPlaybackClock, with RealAuxDcPlaybackClock as the only implementation any shipping code
    path can reach), and the test now runs on a virtual clock through
    DriverTestKit.OnAVirtualClock(). It keeps every claim it made before — which simply become
    decidable — and gains a stronger one: playback visited all four segments, in order. Production
    behaviour is unchanged
    ; the default clock is real time and nothing outside the test assembly can
    replace it.

  • The same defect, six times narrower, found while fixing the first.
    Playback_ClampsToTheSupplyCeilingAndSaysSoRatherThanFailingSilently asserted Assert.NotEmpty
    on an over-range segment only 50 ms wide — the identical bet that a sample lands inside a
    window. It had never been observed failing, which is exactly why it was worth moving to the same
    seam now rather than during some future release.

Added

  • Playback_OnTheRealClockNeverReportsAValueOffTheProfile — the real-clock companion that keeps the
    production timing path covered, asserting only what holds whatever the scheduler does: every
    report self-consistent against the profile, elapsed time non-decreasing, and the supply left on
    the profile's final value. This is the one test the count grows by.

Verified 8 consecutive runs of the class green with a dotnet publish running in another shell —
one run took 5 s against a normal 1 s, so the contention was real — plus the full suite green on an
idle machine.


Installer

ProtectionAI-Setup.msi is a Windows Installer (MSI) package. It installs ProtectionAI in Program Files, creates a Start Menu shortcut, registers Apps & Features uninstall support, and supports in-place major upgrades. ProtectionAI.App.exe is the same application as a self-contained single-file executable, for people who cannot run an installer.

This release is not Authenticode code signed. Windows SmartScreen will warn you when you run it, and that warning is expected. The checks below prove integrity (the bytes are the bytes we built) and source binding (the signed manifest came from this repository, tag and commit). They are not a Windows trust decision and do not stop SmartScreen warning.

Artifact digests (SHA-256)

fbeaf583840971d6a64536f57cc5081e6042a77d722f508ac171f3132ea80955  protectionai-1.7.1-cyclonedx.json
82e19e9e6a2ba534f06346dbcd094fb096f8b930b955b28365e5b5d49825e0e3  protectionai-1.7.1-cyclonedx.json.sha256
36f2e3d729b10ed7fe3701273d2158c4805ce3161c40be68b8615bf5dd12da87  ProtectionAI-Setup.msi
1dd0674b27049cafa52e85af2f705f080bbb20ce6e5ae34b77e17ab51e298233  ProtectionAI.App.exe

Published alongside the artifacts as SHA256SUMS, with a detached Sigstore signature (SHA256SUMS.sig), the ephemeral signing certificate (SHA256SUMS.pem) and a self-contained bundle (SHA256SUMS.cosign.bundle). The software bill of materials (protectionai-1.7.1-cyclonedx.json) and its checksum sidecar (protectionai-1.7.1-cyclonedx.json.sha256) are both attached and covered by the signed manifest.

1. Verify integrity — the files are what we built

PowerShell:

foreach ($line in Get-Content .\SHA256SUMS) {
  $expected, $name = $line -split '\s+', 2
  $actual = (Get-FileHash $name.Trim() -Algorithm SHA256).Hash.ToLower()
  "{0}  {1}" -f $(if ($actual -eq $expected) { "OK  " } else { "FAILED" }), $name.Trim()
}

POSIX shell:

sha256sum -c SHA256SUMS

2. Verify authenticity — the digest list itself is genuine

Step 1 only proves the files match the list. This proves the list was produced by this release workflow. Install cosign and run:

cosign verify-blob SHA256SUMS \
  --signature SHA256SUMS.sig \
  --certificate SHA256SUMS.pem \
  --certificate-identity https://github.com/Cwgtshome/ProtectionAI/.github/workflows/release.yml@refs/tags/v1.7.1 \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  --certificate-github-workflow-repository Cwgtshome/ProtectionAI \
  --certificate-github-workflow-ref refs/tags/v1.7.1 \
  --certificate-github-workflow-sha 22cdeb09aeeed0e5e609748cd878c11a118f7947

Or with the bundle, which needs no separate certificate:

cosign verify-blob SHA256SUMS \
  --bundle SHA256SUMS.cosign.bundle \
  --certificate-identity https://github.com/Cwgtshome/ProtectionAI/.github/workflows/release.yml@refs/tags/v1.7.1 \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  --certificate-github-workflow-repository Cwgtshome/ProtectionAI \
  --certificate-github-workflow-ref refs/tags/v1.7.1 \
  --certificate-github-workflow-sha 22cdeb09aeeed0e5e609748cd878c11a118f7947

Pin all five certificate constraints exactly as shown: identity, issuer, repository, ref and SHA. Together they reject a signature from another workflow, repository, tag or commit. There is no long-lived private key: the certificate above was issued to this workflow's OIDC identity, is valid for minutes, and the signing event is recorded in the public Rekor transparency log.

3. Build provenance — not available for this release

No GitHub-hosted SLSA build-provenance attestation was recorded, so gh attestation verify will not find one. GitHub's attestation store is not offered to user-owned private repositories on this plan, and the source repository is private.

What still holds: the signed SHA256SUMS manifest binds every shipped content file by digest, and the Sigstore certificate in step 2 binds that manifest to this repository, tag ref and exact source SHA against a public transparency log. What is missing is GitHub's separate SLSA predicate and attestation-store record; no SLSA level is claimed.

Built from Cwgtshome/ProtectionAI@22cdeb0. See docs/RELEASE-INTEGRITY.md for what each file is and why it exists.

ProtectionAI v1.7.0

Choose a tag to compare

@Cwgtshome Cwgtshome released this 03 Aug 06:26

101 registered [WorkspaceView] modules, 30 AI copilot tools, 4 AI providers, 7 UI languages,
3,055 tests. Ribbon: 17 tabs, 85 groups, 144 controls. Unchanged from v1.6.1 — this release adds no
modules, tools or tests. It is a shell and interaction release: the ribbon stops hiding tabs, the
workspace gains the right-click vocabulary a Windows engineer expects, and the interaction colours
stop competing with the colour that means energized.

Added

  • A ribbon tab fit engine, so no tab is ever clipped. Seventeen tabs plus a 520 px search box do
    not fit every window, and Fluent.Ribbon's answer was to scroll-clip the tail of the strip: on a
    1366×768 field laptop the Machines and View tabs were simply not on screen, with nothing to say
    they existed. Office never does this — it bounds the tab count and pushes the remainder through
    overflow — so the shell now measures the strip's real overflow (IScrollInfo.ExtentWidth against
    ViewportWidth) and steps down until it fits: the search box gives up width first (520 → 380 →
    220), then the tab captions compact to the existing short-form scheme, and only then do tabs move
    into a More tabs chevron beside the search box. Tabs are parked from the right end of
    RibbonGlyphs.TabOrder, so the testing tabs — leftmost by design — are the last to go, and the
    selected tab is never parked. Choosing a tab from the menu restores it, selects it and re-fits, so
    every tab stays one or two clicks away at any width.

    Verified in the running app at 1720 / 1000 / 880 px: every visible tab is fully inside the window
    at every width, and a tab that does not fit is in the menu rather than half-drawn at the edge. If
    the tabs panel is ever unmeasurable — a future Fluent.Ribbon template change — the pass falls back
    to the previous fixed-width thresholds instead of leaving a narrow window with seventeen
    full-width tabs.

  • Right-click across the workspace. AvalonDock ships no default tab context menus at all:
    DocumentContextMenu and AnchorableContextMenu are null unless the application supplies them,
    which is why right-clicking a document tab did nothing. Document tabs now carry the VS-style menu
    (Close, Close All But This, Close All, Float, Dock as Tabbed Document, and the four tab-group
    commands), tool-pane captions carry Float / Dock / Auto Hide / Hide, every module ribbon button
    carries Open and Open in floating window — the fastest route to a second-monitor layout —
    and copilot messages carry Copy and Regenerate, which until now existed only as hover affordances
    and were therefore invisible on a touch screen. Every dock item binds to the AvalonDock
    LayoutItem command, so the enabled states are the real ones.

    The tool-pane menu is attached by a class handler rather than through AnchorableContextMenu,
    because a pane holding a single tool window renders a caption title bar with no tab for that
    property to reach — which is why Relay Assets and the AI Copilot had no right-click at all.

  • Middle-click closes a document tab, the Visual Studio and browser convention. The hit is
    resolved geometrically against the tab bounds: an ancestor walk from OriginalSource missed
    clicks landing on tab padding, and a bounds test cannot be wrong about what the operator aimed at.

Changed

  • The ribbon's interaction colours are quiet again. The generated Light.Red / Dark.Red
    ControlzEx themes paint every hovered ribbon button with a saturated accent fill, so moving the
    pointer across the ribbon flashed solid brand red. That is loud next to Word, and it collides
    head-on with this product's rule that saturated red means energize or danger — an operator who
    sees red under the cursor all day stops reading it as a warning. The six hover / pressed / checked
    brushes are re-pointed at the same ControlFill* and SelectionAccent tokens every other control
    in the shell uses. Pixel-sampled in the running app: hover is a uniform neutral grey, and no
    ribbon button carries red at rest.

  • The selected ribbon tab's caption takes its category accent — the colour its own icons already
    use — so the tab strip carries the same Office-style category identity as the buttons beneath it.

  • The emergency stop is now an ISO 13850 signature. The ■ STOP (F12) control sits on a fixed
    safety-yellow field: red-on-yellow is the emergency-stop pairing of ISO 13850 and IEC 60204-1 and
    the strongest learned danger signal in industry. It is deliberately theme-invariant — safety
    chrome does not follow the light/dark preference — and the pairing appears nowhere else in the
    application, so it cannot be confused with ordinary UI.

  • Button corner radii move to the Fluent 2 standard 4 px for in-page controls.

Fixed

  • The document tab strip rendered light chrome in the dark theme — a white active tab and
    gradient unselected tabs — which is the one piece of the shell that still looked like a different
    application. The suspected cause was wrong: every VS2013 ResourceKeys mapping in
    ApplyDockInteractionPalette was resolving and applying correctly. The style AvalonDock assigns
    to the strip's TabItem containers simply never consults that key set. Each dock tab now takes a
    style derived from whatever base AvalonDock assigned — keeping its template, header, close
    button and drag behaviour — overriding only the state brushes with SurfaceAlt,
    ControlFillHover, ControlFillSelected and TextPrimary. It is applied by a class handler with
    one deferred retry, because the container's DataContext and style are assigned after Loaded
    fires, which is why a naive handler silently did nothing.

    Both the palette helper and the tab strip now log what they resolved
    (DockPalette: all mappings applied., DockTabDiag: … bg=#FF1E1E1E), so the next regression is
    readable from the log instead of invisible. Silent no-op reflection is what let this survive
    several releases.


Installer

ProtectionAI-Setup.msi is a Windows Installer (MSI) package. It installs ProtectionAI in Program Files, creates a Start Menu shortcut, registers Apps & Features uninstall support, and supports in-place major upgrades. ProtectionAI.App.exe is the same application as a self-contained single-file executable, for people who cannot run an installer.

This release is not Authenticode code signed. Windows SmartScreen will warn you when you run it, and that warning is expected. The checks below prove integrity (the bytes are the bytes we built) and source binding (the signed manifest came from this repository, tag and commit). They are not a Windows trust decision and do not stop SmartScreen warning.

Artifact digests (SHA-256)

0e59b04d2dc92b5cd32805483a8a6316496dc8d6ef53921c24d88b9011d3cbf1  protectionai-1.7.0-cyclonedx.json
0cdc94079619f3e152f714b2fda98dca36eb1dbc6afed3674b778a6257b5129c  protectionai-1.7.0-cyclonedx.json.sha256
01ceef4617c81251f869ae7b3e5535b7c9e0b3461afc5a6c5579a7acbca02012  ProtectionAI-Setup.msi
919595c01c18a03fc461bf5a0887f82a495df20aa5aac4258e02e1d5c069acd1  ProtectionAI.App.exe

Published alongside the artifacts as SHA256SUMS, with a detached Sigstore signature (SHA256SUMS.sig), the ephemeral signing certificate (SHA256SUMS.pem) and a self-contained bundle (SHA256SUMS.cosign.bundle). The software bill of materials (protectionai-1.7.0-cyclonedx.json) and its checksum sidecar (protectionai-1.7.0-cyclonedx.json.sha256) are both attached and covered by the signed manifest.

1. Verify integrity — the files are what we built

PowerShell:

foreach ($line in Get-Content .\SHA256SUMS) {
  $expected, $name = $line -split '\s+', 2
  $actual = (Get-FileHash $name.Trim() -Algorithm SHA256).Hash.ToLower()
  "{0}  {1}" -f $(if ($actual -eq $expected) { "OK  " } else { "FAILED" }), $name.Trim()
}

POSIX shell:

sha256sum -c SHA256SUMS

2. Verify authenticity — the digest list itself is genuine

Step 1 only proves the files match the list. This proves the list was produced by this release workflow. Install cosign and run:

cosign verify-blob SHA256SUMS \
  --signature SHA256SUMS.sig \
  --certificate SHA256SUMS.pem \
  --certificate-identity https://github.com/Cwgtshome/ProtectionAI/.github/workflows/release.yml@refs/tags/v1.7.0 \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  --certificate-github-workflow-repository Cwgtshome/ProtectionAI \
  --certificate-github-workflow-ref refs/tags/v1.7.0 \
  --certificate-github-workflow-sha c53ad4edf98c596d0a2f241c2af7d402c528905d

Or with the bundle, which needs no separate certificate:

cosign verify-blob SHA256SUMS \
  --bundle SHA256SUMS.cosign.bundle \
  --certificate-identity https://github.com/Cwgtshome/ProtectionAI/.github/workflows/release.yml@refs/tags/v1.7.0 \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  --certificate-github-workflow-repository Cwgtshome/ProtectionAI \
  --certificate-github-workflow-ref refs/tags/v1.7.0 \
  --certificate-github-workflow-sha c53ad4edf98c596d0a2f241c2af7d402c528905d

Pin all five certificate constraints exactly as shown: identity, issuer, repository, ref and SHA. Together they reject a signature from another workflow, repository, tag or commit. There is no long-lived private key: the certificate above was issued to this workflow's OIDC identity, is valid for minutes, and the signing event is recorded in the public Rekor transparency log.

3. Build provenance — not available for this release

No GitHub-hosted SLSA build-provenance attestation was recorded, so gh attestation verify will not find one. GitHub's attestation store is not offered to user-owned private repositories on this plan, and the source repository is private.

What still holds: the signed SHA256SUMS manifest binds every shi...

Read more

ProtectionAI v1.6.1

Choose a tag to compare

@Cwgtshome Cwgtshome released this 02 Aug 19:11

101 registered [WorkspaceView] modules, 30 AI copilot tools, 4 AI providers, 7 UI languages,
3,055 tests. Ribbon: 17 tabs, 85 groups, 144 controls. Unchanged from v1.6.0 — this release adds no
modules, tools or tests; it fixes one way the product could lose a user's data.

Fixed

  • A second instance could corrupt the database. Nothing prevented two copies of ProtectionAI
    running at once, and everything the product persists — assets, settings versions, archived
    sessions, the document repository — lives in one per-user protectionai.db. Two processes writing
    that file is how it gets damaged: the development machine recorded three
    SQLite error 11 — database disk image is malformed quarantines in a single day while copies were
    being started side by side.

    ProtectionDatabase already recovered from this properly — the damaged file is moved aside with
    its -wal and -shm sidecars, never deleted, and a note beside it gives the sqlite3 .recover
    salvage command — but recovery still costs every test record written since the last export, and
    the user only finds out on the next launch. Preventing the second writer is the other half of the
    fix.

    A named mutex is now taken in Services\SingleInstance.cs before anything opens the database, and
    ahead of the EULA and licence gate, so a second launch costs nothing and shows no dialogs: it
    raises the window that is already open and exits. The name carries the user's SID in the global
    namespace, making the guard per user rather than per session — a remote session running
    alongside a console one shares %AppData%, and therefore shares the database. Two different users
    have separate data directories and are unaffected.

    An abandoned mutex counts as acquired, because the previous owner exiting without releasing is the
    normal case here (this repository's own build steps force-kill the app); OnExit releases it on a
    clean shutdown so that path stays distinguishable from a crash in the log.
    --allow-multiple-instances remains for running two builds side by side and logs what it costs,
    rather than being a silent hole.

    Verified against the published build rather than by unit test, which is the stronger evidence for
    an OS-level guard: the second launch is refused and the first activated, the override switch runs
    two and logs the warning, and a clean shutdown releases the name.


Installer

ProtectionAI-Setup.msi is a Windows Installer (MSI) package. It installs ProtectionAI in Program Files, creates a Start Menu shortcut, registers Apps & Features uninstall support, and supports in-place major upgrades. ProtectionAI.App.exe is the same application as a self-contained single-file executable, for people who cannot run an installer.

This release is not Authenticode code signed. Windows SmartScreen will warn you when you run it, and that warning is expected. The checks below prove integrity (the bytes are the bytes we built) and source binding (the signed manifest came from this repository, tag and commit). They are not a Windows trust decision and do not stop SmartScreen warning.

Artifact digests (SHA-256)

8883c576dc5805ef9737837b616ab2f45ee9006180da34e65c505766ab88dc1c  protectionai-1.6.1-cyclonedx.json
356463bff1e3728d44492d6ec33b7e2cf9019118b8fb7f9640e4794e624c9a0c  protectionai-1.6.1-cyclonedx.json.sha256
4d17b7795182fd8c862e4b8ce82ba172039a4dbaf3c8d64b78714b76da04c7e5  ProtectionAI-Setup.msi
8401fa04b12d645b930bde6a554539a0a435b2dd3139f86b55b2f73ece5f7f81  ProtectionAI.App.exe

Published alongside the artifacts as SHA256SUMS, with a detached Sigstore signature (SHA256SUMS.sig), the ephemeral signing certificate (SHA256SUMS.pem) and a self-contained bundle (SHA256SUMS.cosign.bundle). The software bill of materials (protectionai-1.6.1-cyclonedx.json) and its checksum sidecar (protectionai-1.6.1-cyclonedx.json.sha256) are both attached and covered by the signed manifest.

1. Verify integrity — the files are what we built

PowerShell:

foreach ($line in Get-Content .\SHA256SUMS) {
  $expected, $name = $line -split '\s+', 2
  $actual = (Get-FileHash $name.Trim() -Algorithm SHA256).Hash.ToLower()
  "{0}  {1}" -f $(if ($actual -eq $expected) { "OK  " } else { "FAILED" }), $name.Trim()
}

POSIX shell:

sha256sum -c SHA256SUMS

2. Verify authenticity — the digest list itself is genuine

Step 1 only proves the files match the list. This proves the list was produced by this release workflow. Install cosign and run:

cosign verify-blob SHA256SUMS \
  --signature SHA256SUMS.sig \
  --certificate SHA256SUMS.pem \
  --certificate-identity https://github.com/Cwgtshome/ProtectionAI/.github/workflows/release.yml@refs/tags/v1.6.1 \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  --certificate-github-workflow-repository Cwgtshome/ProtectionAI \
  --certificate-github-workflow-ref refs/tags/v1.6.1 \
  --certificate-github-workflow-sha 6201ed4218343af77392b1b8653f0ff077164c3f

Or with the bundle, which needs no separate certificate:

cosign verify-blob SHA256SUMS \
  --bundle SHA256SUMS.cosign.bundle \
  --certificate-identity https://github.com/Cwgtshome/ProtectionAI/.github/workflows/release.yml@refs/tags/v1.6.1 \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  --certificate-github-workflow-repository Cwgtshome/ProtectionAI \
  --certificate-github-workflow-ref refs/tags/v1.6.1 \
  --certificate-github-workflow-sha 6201ed4218343af77392b1b8653f0ff077164c3f

Pin all five certificate constraints exactly as shown: identity, issuer, repository, ref and SHA. Together they reject a signature from another workflow, repository, tag or commit. There is no long-lived private key: the certificate above was issued to this workflow's OIDC identity, is valid for minutes, and the signing event is recorded in the public Rekor transparency log.

3. Build provenance — not available for this release

No GitHub-hosted SLSA build-provenance attestation was recorded, so gh attestation verify will not find one. GitHub's attestation store is not offered to user-owned private repositories on this plan, and the source repository is private.

What still holds: the signed SHA256SUMS manifest binds every shipped content file by digest, and the Sigstore certificate in step 2 binds that manifest to this repository, tag ref and exact source SHA against a public transparency log. What is missing is GitHub's separate SLSA predicate and attestation-store record; no SLSA level is claimed.

Built from Cwgtshome/ProtectionAI@6201ed4. See docs/RELEASE-INTEGRITY.md for what each file is and why it exists.

ProtectionAI v1.6.0

Choose a tag to compare

@Cwgtshome Cwgtshome released this 02 Aug 14:59

101 registered [WorkspaceView] modules (was 95), 30 AI copilot tools (was 27), 4 AI providers,
7 UI languages, 3,055 tests. Ribbon: 17 tabs, 85 groups, 144 controls.

Commands that produced them:

powershell -NoProfile -ExecutionPolicy Bypass -File scripts\check-counts.ps1   # 101 modules, 30 tools
dotnet test tests\ProtectionAI.Tests -m:1 -nodeReuse:false                     # 3,055 passed / 0 failed

The theme of the wave is coverage of relay models and of the path from a settings file to a
reviewable test plan
. Two of the three headline numbers are content, not code, and the honesty
question they raise is answered the same way throughout: a relay model's identity can be verified
from public sources; its settings and tolerances cannot, and anything generated from the former is
labelled an unverified estimate.

Added — relay model coverage

  • Seven more curated relay packs, 14 → 21. ABB REF615 joins RED615 and RET615; Basler adds
    BE1-CDS220 alongside BE1-11f; GE adds F60 and L90 to D60/T60; MiCOM adds P642 to P143/P543; SEL
    adds 311C and 751 to 351/387E/421. Same schema, same per-parameter citation requirement as the
    v1.4.0 packs — a pack row states whether its tolerance came from a published specification or is
    an engineering estimate, and says which. Count with
    (Get-ChildItem src\ProtectionAI.Core\Templates\Packs\*.json).Count and subtract
    packs.schema.json (the folder holds 22 files).
  • A relay model catalog — 539 entries. Templates\Catalog\*.json, loaded by RelayCatalog,
    compiled in two research rounds: the first covering the current lines of SEL, GE, ABB/Hitachi,
    Siemens/Reyrolle, Schneider heritage (MiCOM/Sepam/VAMP), the Asian manufacturers and the US/EU
    specialists; the second adding the legacy electromechanical and solid-state families utilities
    still test daily (Westinghouse CO, GEC Quadramho/Optimho, SIPROTEC 3-era) plus SEG/Woodward,
    Thytronic, Efacec, Sifang, Hyundai, LS Electric, Ashida and the recloser-control makers. Each entry
    carries manufacturer, family, model, a one-line description, category, the principal ANSI device
    numbers, current/legacy status, and the public sources each was checked against, with URLs.
    Models that could not be verified against a vendor page or manual were excluded rather than
    pattern-completed from a series naming grid — ABB's REQ670, for instance, does not exist.
  • What the catalog is and is not. The verified facts are: the model exists, who makes it, what it
    protects, and which functions it documents. Nothing else. CatalogPackFactory materializes a
    catalog entry into a family-generic pack for the Relay Template Library, and every numeric value
    it generates is written as PackVerification.UnverifiedEstimate with a citation naming the
    standard convention it derives from. Generic rows deliberately carry no settable min/max,
    because ranges are model-specific facts nobody has verified. Every materialized pack and every
    generated plan carries CatalogPackFactory.ProvenanceNote verbatim.
  • Total relay models representable: 560 — 21 detailed packs plus 539 catalog entries. Those two
    tiers are not interchangeable and must never be added together without saying which is which: the
    21 have per-parameter provenance, the 539 have verified identity and estimated numbers.
  • The Relay Template Library browser gains a catalog section: search the 539 identities and create a
    template from one, with the provenance statement shown next to it. A malformed shipped catalog is
    reported on screen as a build defect rather than hidden.

Added — from a settings file to a reviewable plan

  • Vendor settings-file importers (Core\Templates\Import\): SEL ASCII text, DIGSI 5 XML, and a
    generic name/value CSV/TXT reader, alongside the existing RIO/XRIO path.
    SettingsImportDetector picks the reader by content sniff, and proprietary binary containers
    (ACSELERATOR .rdb and friends) are refused
    rather than read as text into a garbage import.
  • Settings Import module (Database ▸ Settings). Previews every parameter with its mapped or
    unmapped status, surfaces unparseable lines as warnings instead of guessing values, always prints
    the source format and the mapped/unmapped counts as provenance, and can promote the result to the
    application-wide active relay model through the same API the XRIO import uses.
  • TestPlanGenerator turns an active settings model into a TestPlan: a pickup ramp and timing
    shots per enabled overcurrent element (×2/×3/×5 inverse-time, ×1.5/×3 definite-time), a check shot
    per enabled distance zone, and differential characteristic points across the slope regions.
    Anything configured that the existing step types cannot express is written into the plan as an
    explicit note — never a silent skip.
  • Plan Generator module (Templates ▸ Test Plans). The generated plan is a starting point derived
    mechanically from settings; nothing in it is a measurement, it is saved to the template library
    only when the operator chooses to, and it carries a description saying a qualified protection
    engineer must review it before use. Where a built-in pack matches the active model the pack's
    published tolerance bands and their verification provenance are quoted; otherwise the IEC 60255
    convention defaults are stated as the defaults they are.
  • A seeded test-plan template library — 12 starter plans in Core\Templates\Seeds\, installed by
    TemplateSeeder behind a version-suffixed marker file so a re-run does not duplicate them:
    definite-time and IDMT overcurrent (50, 51), directional and negative-sequence overcurrent (67,
    46), distance zones (21), transformer differential (87T), breaker failure (50BF), autoreclose (79),
    synchronism check (25), frequency (81), voltage (27/59) and thermal overload (49).

Added — modules

Six new registered workspaces (95 → 101). The ribbon grew by exactly six controls and two groups
(Database ▸ Settings and Templates ▸ Test Plans are the first registered views on those two tabs;
the other four joined existing groups). Verify with
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\check-counts.ps1, not by adding up the
bullets below — this line said "five" and "95 → 100" until COMTRADE Replay landed later in the same
wave, which is exactly the arithmetic a reader would otherwise carry forward.

  • Settings Import (Database) and Plan Generator (Templates), described above.
  • Fleet Dashboard (Enterprise ▸ Overview) — age-of-last-test buckets across the asset register,
    stat cards, a per-substation heat list, the monthly archived-result trend and a sortable
    drill-down, all computed by FleetStats. Scope is stated on the page: every figure comes from
    the sessions archived in this ProtectionAI database only, testing recorded elsewhere is invisible
    to it, and the 12/24-month thresholds are review aids, not a PRC-005 compliance determination
    the Compliance view still owns that.
  • Integrations (Enterprise ▸ Overview) — file-based interoperability: an RFC 5545 .ics export
    of upcoming maintenance and scheduled work, a work-order CSV in generic, IBM Maximo or SAP PM
    column sets, and a pre-filled mailto: draft about the current session. That file-based half needs
    no credentials and is always available. Later in this same wave the view also gained an optional
    live half
    — WhatsApp Cloud, Slack, Microsoft Graph (mail and calendar), IBM Maximo and SAP PM,
    each driven by credentials the customer supplies and stores DPAPI-encrypted on their own machine.
    Those clients are written against the vendors' public API documentation and are certified or
    endorsed by none of them
    ; every send is user-initiated behind a confirmation naming exactly what
    goes where, and the vendor's own error text is shown verbatim rather than being interpreted.
    "EAM integration" still overstates it: this is a customer-credentialled REST call, not a
    supported, vendor-tested connector.
  • GOOSE Trip Transfer Time (Advanced ▸ Protocols) — publishes a test GOOSE state change with the
    simulation bit set on every frame and times the hand-off against the IEC 61850-5 classes (TT6 3 ms,
    TT5 10 ms, TT4 20 ms, TT3 100 ms). Transport provenance is printed with every figure. On the
    deterministic loopback both timestamps come from this application's clock, so the number is an
    in-process encode/dispatch/decode latency — a workflow and codec check, not network evidence. On a
    named Npcap interface the frames are real and the detection timestamp is a software capture
    timestamp: evidence about this host's publish-to-capture path on an isolated network, not about
    an IED's application-to-application transfer time, which spans two devices and both their stacks.
    Timestamp uncertainty is carried through and a class the uncertainty cannot support is refused.
  • COMTRADE Replay (Test ▸ Waveform) — the view over the replay engine described below. It reads a
    .cfg/.dat pair through the existing Comms COMTRADE reader, projects each channel to secondary
    engineering units, previews the record on the waveform scope, maps channels to driver outputs and
    then runs the full injection contract: isolation attestation, timed phasor segments applied against
    one schedule clock, the watched binary input awaited with a timeout, the trip time assessed through
    ToleranceAssessor and recorded. It refuses out-of-range records by name and peak before
    energizing anything, and it carries ComtradeReplay.ProvenanceStatement on every surface: the
    record is replayed as cycle-by-cycle phasor segments, not as samples.

Added — drivers

  • Generic SCPI source (TCP) — a third implemented driver in DriverRegistry, selectable in
    production alongside the simulator and the OMICRON CM Engine adapter. It speaks SCPI-1999 over a
    raw TCP socket to a prog...
Read more