ProtectionAI v1.9.0
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
diffoffers 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:ovcis 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 searchingo/cemphasises 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.SendAsyncappends 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 onconfirmed_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 throughTst.ReadyAsyncand 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 SHA256SUMS2. 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 0616546e08661fa2ee448870ff0a022faba94351Or 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 0616546e08661fa2ee448870ff0a022faba94351Pin 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@0616546. See docs/RELEASE-INTEGRITY.md for what each file is and why it exists.