Skip to content

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 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@c53ad4e. See docs/RELEASE-INTEGRITY.md for what each file is and why it exists.