Contract-Neutral: E2E test tier metadata and validation only; no deployment runtime or public contract change.
Co-authored-by: Pulse Autonomous Maintainer <rcourtman@users.noreply.github.com>
Production SignPath signing requests require manual approval in the
SignPath UI, so the previous single-job flow (submit with
wait-for-completion inside a 40-minute window) let approval latency fail
the Windows build, and any re-run rebuilt the binaries and submitted a
second request needing a second approval.
The Windows lane is now two jobs: sign-windows-agent builds the unsigned
executables, submits the SignPath request without waiting, and uploads a
7-day signing-request record; collect-windows-signing absorbs approval
latency by polling the recorded request, downloads the signed artifact
by request id, and keeps the existing verification and evidence steps.
If approval outlasts the 115-minute polling window, the collection job
fails with re-run guidance and "Re-run failed jobs" collects the same
recorded request - no rebuild, no resubmission. The legacy PFX
break-glass backend rides the same two-job shape via an artifact
hand-off. Workflow output wiring, artifact names, and evidence content
are unchanged for downstream consumers.
The shape test now pins the async invariants (no wait-for-completion:
true in the candidate workflow), and the code signing policy plus the
deployment-installability contract describe the two-phase flow.
Two failures landed this morning:
- test_gitleaks_ignore.py's historical-fingerprint resolution (added in
d1fa7f38c) needs branch- and tag-reachable history, but the
scripts-and-build job used a depth-1 checkout, so all 37 fingerprints
failed to resolve in CI. Fetch full history like the gitleaks and
changes jobs already do.
- d1f687c0e routed frontend-modern/package.json and package-lock.json to
the new frontend-dependency-security path policy without updating the
manifest expectations pinned in test-hot-dev-bg.sh. Pin the effective
first-match policy per manifest instead of bare membership so the
routing stays asserted and shadowed entries cannot fake coverage.
Contract-Neutral: CI-only fix: full-history checkout for gitleaks fingerprint resolution test and re-pin hot-dev manifest policy expectations to the registry routing d1f687c0e already established; no contract delta
The pre-commit frontend formatter resolved prettier at
REPO_ROOT/frontend-modern/node_modules/.bin/prettier, where REPO_ROOT is
derived from the script's own path. In a linked worktree that is the
worktree root, which never runs npm install, so prettier_bin() returned
None and the formatter silently returned 0. Every frontend commit made
from a Claude or Codex agent worktree skipped formatting entirely, and
the drift accumulated in already-committed files until someone ran
`make format` and picked up 14 files of unrelated churn.
The skip path's comment claimed "CI's prettier check still catches drift
that slips through here." No such check existed -- nothing under
.github/workflows referenced prettier -- so there was no backstop at all.
- Fall back to the primary worktree's node_modules, resolved via
`git rev-parse --git-common-dir`, and say so in the hook output so a
version mismatch between the two checkouts stays visible.
- Add the whole-tree "Check frontend formatting" step to the frontend CI
job that the comment already promised. Staged-only formatting cannot
see drift in untouched files; this can.
- Pin prettier exactly. "^3.3.0" let the tracked package-lock.json land
on 3.9.5 while the gitignored pnpm-lock.yaml resolved 3.9.6, so CI and
the dev machine were free to run different formatters.
- Resolve the test suite's prettier the same way, so its two real
coverage tests stop silently skipping in worktrees.
Contract-Neutral: devDependency prettier version pin plus pre-commit/CI formatter tooling; no runtime, API, or deployment-surface delta
The agent_runtime verify-only build pointed its registry buildcache at
ghcr.io/<owner>/pulse-agent, a package no workflow publishes. A cache ref
creates the package it points at, so every release recreated it and the
repository's Packages sidebar advertised an empty pulse-agent entry that
reads like a pullable agent image sitting beside the real pulse,
pulse-control-plane and pulse-chart/pulse packages. The only release tag it
ever carried is a stray v6.0.0-rc.3.
Move the cache to ghcr.io/<owner>/pulse:agent-buildcache, alongside the
runtime stage's existing pulse:buildcache tag, so it lives in the package
that actually ships and shares backend-builder layers with the runtime
build.
TestAgentBuildCacheDoesNotResurrectPulseAgentPackage locks this in. It scans
every workflow for registry-qualified refs to the pulse-agent package,
collapsing ${{ }} expressions first so an interpolated owner cannot hide one
behind its spaces, and asserts both the new cache target and the chart's
published agent image default. Verified red on a restored buildcache ref and
red again on a ref hidden behind ${{ github.repository_owner }}.
Two stale claims corrected while here. The chart values comment said the old
agent.image default was never published, when it did carry v6.0.0-rc.3. The
deployment-installability contract called rcourtman/pulse the only image
publish-docker.yml pushes, when the same workflow also pushes the MSP
pulse-control-plane image. The contract now also forbids buildcache
references to the pulse-agent package, which is what let this regress.
Deleting the orphaned package itself remains a manual GHCR step.
40d29ca44 rewrote the public repository surface and tripped four standing
guards. Reinstate the signed-installer verification snippet and pinned
pulse-installer ed25519 key in README.md, use native-language names for
the localized guide links, point the issue-template docs contact link at
a stable non-branch-tip URL, and resync the shipped copies under
frontend-modern/public/docs with their repo sources.
Fixes CI on main (runs 31058322973, 31058903048).
The paid-runtime R2 prefix was derived from the wall-clock date, and the
enterprise build was always dispatched as a fresh rebuild. Rerunning the
failed publish job after a transient promotion failure therefore hit the
enterprise R2 overwrite guard (same run id, existing prefix) and the
Definitive Release Verdict could never go green by rerun, as on
v6.2.0-rc.6. The prefix date now comes from the run's createdAt, which
is stable across rerun attempts, and the build dispatch passes
reuse_existing_packet=true so pulse-enterprise validates the packet the
earlier attempt uploaded, skips the rebuild, and only the promotion
re-executes against it. The deployment-installability contract now
records rerun recoverability as part of the promotion boundary.
v6.2.0-rc.5 shipped with an empty Proxmox workloads table and a crashing
Thresholds page (#1663) while the assertions that catch exactly that were
failing in CI: spec 64 red in the non-gating probation tier two hours
before the tag, and the gating Core E2E verdict red on the release commit
itself — which the release pipeline never consults. integration_tests is
also skipped entirely for prereleases, so the builds users test shipped
with no integration coverage at all.
Close the hole with a release_smoke job that runs for every cut,
prereleases included, and blocks create_release and the release verdict:
four interaction-free render assertions (Proxmox nodes+workloads, Docker
hosts+containers, Kubernetes clusters+pods, Alert thresholds) against the
mock-mode image built from the verified frontend bundle. The mock fixture
graph now always contains one freshly provisioned zero-used guest
filesystem, so the omitted-zero-numerics wire shape that crashed rc.5
stays exercised on every mock-backed surface. Verified locally: the suite
passes on main and fails on the rc.5 frontend for exactly the two shipped
regressions.
The Build and Test workflow ran everything in one serial job — frontend
lint/tests/build, the full go test -race sweep, and benchmarks — for a
37-55 minute wall clock on every push. The job now splits into parallel
jobs: frontend (lint, unit tests, type-check, bundle build and size gate),
backend tests sharded three ways with internal/api on its own shard since
it alone takes ~10m under -race, script smoke tests with the backend
build, and benchmarks with the existing baseline cache flow. Backend jobs
satisfy the frontend embed with a stub index.html, which unit tests do
not assert against; the real bundle is still built and size-gated by the
frontend job and by release builds. Expected wall clock is roughly the
slowest single job, 10-15 minutes.
A new changes job skips the build/test jobs when a push touches only
docs/ and Markdown, mirroring the path filters Core E2E already has. The
gitleaks secret scan deliberately stays unconditional since this workflow
is the only per-push scan and docs can leak secrets too.
scripts/dev-prepush.sh runs the checks that most often turn main red,
scoped to the outgoing commits: the canonical completion guard in CI
mode, the registry snapshot tests when registry.json changed, the
mutation registry audits, build plus tests for touched Go packages, and
the frontend type-check. It exists because CI verdicts arrive well after
the push; today's unclassified force-fail route would have failed it
locally in about a minute.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
normalizeVersion matched /\bv?(\d+\.\d+\.\d+...)/ without the i flag, so a
reported version written as "V6.0.4" never parsed.
The heading regexes in extractPulseVersion already carry the i flag and did
capture "V6.0.4" correctly, but they hand the captured string to
normalizeVersion, which then returned null. That collapsed every extraction
path -- inline scan, heading match, legacy match, and title fallback -- so the
issue was labelled needs-version-info despite stating its version.
Adding the i flag to normalizeVersion fixes all four paths at once. It is a
no-op on the rest of the pattern, since [0-9A-Za-z.-] already spans both cases.
Seen on #1538, which stated "V6.0.4" under the "Pulse version" heading and was
wrongly flagged as missing version metadata.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Keep macOS notarization mandatory for every release candidate while requiring Windows Authenticode only for stable promotion, matching the publish workflow and RC4 release packet.
Mined per-spec failure data from the 32 completed Core E2E main runs
since the 2026-07-18 quarantine delist (failed-shard logs; a green
shard means every spec in it passed). 26 specs failed or retry-flaked
within the 10 most recent completed runs; they seed PROBATION_SPECS in
tests/integration/playwright.config.ts. The remaining 62 files form the
stable tier and are the only specs that can fail the e2e-verdict job.
Mechanism extends the existing quarantine list rather than adding a
parallel one: PULSE_E2E_TIER=stable ignores probation specs,
PULSE_E2E_TIER=probation runs only them, unset runs the full suite
(local behavior unchanged). CI runs both tiers per shard against the
same containers; the probation pass sits behind continue-on-error with
its own report/results dirs and artifacts, so a probation flake is
reported in the shard summary without painting main red.
Promotion rule, documented next to the list: a probation spec promotes
to stable after 10 consecutive green main runs with no failure and no
retry-flake; one incident on main demotes a stable spec back. In the
newest completed run (29729544151) every failure was in a probation
spec — under this split that run's verdict is green.
Contract-Neutral: CI-only E2E tier split: gating semantics of push-CI verdict; local npm test behavior and dev-runtime orchestration unchanged, no public contract delta