Commit Graph

2459 Commits

Author SHA1 Message Date
pulse-triage[bot] fabcda039b Merge published workload identity recovery into reviewed maintenance
Retain every reviewed starting commit and the refreshed exact published workload identity source additively. PR2888 remains unchanged pending its completed qualification defects; this unproposed composition requires exact final-source checks before the later publication batch.

Change-source: pulse-maintainer
2026-10-13 00:10:38 +01:00
rcourtman 668c5135c7 Keep workload identity stable across node moves (#2882)
A Proxmox node move changed the workload row key, reset an open drawer’s
History view and could publish new coordinates before saved guest
metadata migrated. Rows now use the stable unified resource ID,
bookmarks resolve through the registry, and the selected resource owns
its drawer tab and History range across regrouping.

Accepted publication migrates metadata before exposing the new node. A
failed write retains operator fields in memory and the last successful
disk snapshot, with recovery through the existing writer. Native
metadata and History coordinates remain separate from row identity.
Backend metrics targets take precedence over the legacy native fallback.

Route focus owns initial positioning. Viewport initialization measures
the selected row without replacing its reveal window. Local row clicks
retain their scroll position, while later scroll and resize events
follow the viewport. Operator policy, Assistant, all four Patrol modes
and paid entitlements are preserved.

The proof registry owns the focused publication and writer tests. Its
guard verifies acceptance and rejection without duplicating the catalog.
Canonical and browser guards share exact Git inheritance reads, so
updating a branch retains parent qualification for unchanged content.
New resolutions and mode changes still need current proof, and range
checks qualify the complete proposed change.

Validation:

- Regression controls reproduce publication ordering and persistence
failures. Targeted backend and race tests pass.
- Final repair checks pass: 476 tests across 15 frontend files,
type-check, production frontend build and embedded build.
- Current-source browser checks on /proxmox/overview at 1280x800,
900x800 and 390x844 cover VM and LXC, canonical and legacy links, node
regrouping, native and explicit History targets, saved links, reload,
keyboard selection, Collapse, Escape and search reselection.
- Additional desktop and phone checks cover operator policy persistence,
metadata write failure, delayed lookup cancellation and refused
references. The final browser matrix passes 196 checks.
- Merge-qualification regression reproduces inherited additions, renames
and deletions being misclassified. All 216 focused guard tests pass,
including retained mode changes, new resolutions and ordinary commits.

Browser node movement uses controlled resource updates. Publication and
metadata ordering are verified independently with filesystem barriers
and failure injection.

Refs #1669

The script-smoke fixture includes the shared repository I/O dependency.
All 23 prepush fixture tests pass.
2026-10-13 00:08:15 +01:00
pulse-triage[bot] a9bf104d3a Merge published Patrol setup into reviewed maintenance
Preserve the starting reviewed e5c1f39636 and current published Patrol setup/provider guidance additively. Existing PR2888 remains unchanged while its completed qualification defects return to their owner.

Change-source: pulse-maintainer
2026-10-13 00:08:10 +01:00
rcourtman 7c781789e4 Include shared Git helpers in the prepush browser fixture
The browser gate now uses the shared repository I/O module. Exercise its
real dependency in the prepush fixture so smoke tests reach qualification
checks instead of failing during import.

Contract-Neutral: Test fixture dependency only, no application or contract behavior changes.
2026-10-12 23:44:52 +01:00
rcourtman a4d2cdc2b8 Integrate current workload evidence and merge qualification
Keep the current clock and stored-History readout alongside canonical row
selection and resource-owned drawer state.

Use one Git inheritance reader for browser and canonical qualification.
Inherited modes and objects keep their parent proof, while new resolutions
and mode changes remain subject to current contract and proof requirements.
Range checks still qualify the complete proposed change.

Refs #1669
2026-10-12 23:07:52 +01:00
rcourtman 159db4ba3c Set up Patrol on the Patrol page
18 of 60 paid installs on the current telemetry schema have no AI
provider. Getting Patrol running meant three pages: turn on Pulse
Intelligence, pick one of 14 providers and paste a key, choose a model
from a raw list, then find Check Patrol model on another page.

When Patrol is blocked because no provider is connected, Pulse
Intelligence is off, or the provider refused the saved key, the setup
card now connects a provider in place. It covers a cloud API key
(Anthropic, OpenAI, Gemini, DeepSeek, OpenRouter) or Ollama, names the
model Pulse will use from the Patrol guidance table, prices it before
anything is saved, then saves it, runs the provider test and the Patrol
model check, and offers the first run. A per-token model on the
untouched 6-hour schedule gets the same slower schedule Patrol settings
would propose. Everything else stays on Provider & Models.

The panel stays mounted once started, because polling flips the
readiness cause mid-setup and would otherwise remove the verdict. A
refused key (provider_auth) now routes to Provider & Models instead of
the model check, which could not fix it.
2026-10-12 22:08:37 +01:00
pulse-triage[bot] bcd7f43985 Describe beta.2 customer outcomes against its exact stable-based source
Replace generic fallback notes with source-bound customer changes, preserve signed installer and rollback advice, and correct the canonical cumulative changelog range. Cover meaningful notes, source range and safe rendering with regression checks. This is a notes-only candidate, not a live release edit.

Contract-Neutral: Customer notes, changelog introduction and note-content regression tests only; no runtime, source tag, version, asset, maturity, latest-release or release-cadence change.
Change-source: pulse-maintainer
2026-10-12 21:24:29 +01:00
pulse-triage[bot] 6d187a879b Retain the confined DSM caller window after NAS teardown retirement
Rebind its old next-platform sentinel and include the production NAS selector. The fixture otherwise reaches unrelated runtime cleanup and correctly refuses a non-fixture path. Keep that filesystem guard and every existing DSM safety assertion unchanged.

Change-source: pulse-maintainer
2026-10-12 20:30:49 +01:00
pulse-triage[bot] d87785172e Keep removal regression assertions aligned with explicit NAS ownership
Require the actual NAS quiescence/retirement caller rather than the removed best-effort autorun cleanup. Preserve Upstart exclusion from SysV while requiring the NAS exclusion too. No manager or process safety control is removed.

Change-source: pulse-maintainer
2026-10-12 20:06:06 +01:00
pulse-triage[bot] 4233fc9e56 Observe NAS boot and process closure at each real uninstall phase
The closed signal and server doubles record the current boot/process state without changing outcomes. Require exact boot absence before both signals and complete quiescence at the server boundary, so a future ordering regression cannot pass on final state alone.

Change-source: pulse-maintainer
2026-10-12 19:56:29 +01:00
pulse-triage[bot] 5dad231852 Retain NAS recovery when a live Unraid boot shell owns pending commands
A go shell can hold later launches in memory after its boot file changes. Treat that live mixed-purpose owner as unknown rather than signalling it or inferring quiescence from the edited file. Require the actual-caller refusal control alongside the existing NAS suite.

Change-source: pulse-maintainer
2026-10-12 19:51:00 +01:00
pulse-triage[bot] 450d521e60 Bind the NAS watchdog control to the complete QNAP renderer
The renderer heredoc contains nested shell functions. Extract through its own EOF and outer closing brace so the real private process control executes the complete producer; retain renderer diagnostics on failure.

Change-source: pulse-maintainer
2026-10-12 19:45:42 +01:00
pulse-triage[bot] edb4b922f3 Retain NAS agent recovery until boot and watchdog owners are quiescent
Retire only exact Unraid and QNAP boot entries before checked watchdog-first process termination and same-instance server removal. Preserve unrelated boot owners and refuse unknown, partial or concurrent state without erasing credentials or restarting. Exercise the complete uninstall caller and generated private watchdogs.

Change-source: pulse-maintainer
2026-10-12 19:41:13 +01:00
rcourtman 549a4ca821 Keep workload identity stable across node moves
Use unified resource IDs for workload rows and selection so moving a guest
between Proxmox nodes retains its open drawer and History range. Resolve
existing bookmarks through the registry instead of rebuilding client IDs.

Migrate guest metadata before accepted inventory publication and retain its
operator fields in memory if persistence fails. Native metadata and metrics
coordinates remain explicit compatibility inputs. Operator policy and paid
execution behavior remain intact.

Register the focused publication and writer proofs once. Check proof
acceptance and rejection without copying the registry catalog into tests.

Refs #1669
2026-10-12 19:22:31 +01:00
pulse-triage[bot] 3f63e20216 Refuse incomplete SCALE task activation targets before removal
A missing SCRIPT path or empty COMMAND target cannot establish that a task is unrelated or absent. Retain recovery before any task or service mutation when those fields are unavailable. Add three actual-caller adverse controls to the mandatory sixteen-method hook and both owning contracts.

Change-source: pulse-maintainer
2026-10-12 18:08:19 +01:00
pulse-triage[bot] 59ff0dabcf Retain SCALE agent recovery until every boot task is retired
Disable and independently verify every exact owned middleware activation task before systemd stop and server removal. Close task, unit and process state after the full stop and after task deletion, retaining recovery on refusals or concurrent changes without restarting. Ordinary Linux state directories are not appliance identity. Register all fifteen actual-function/full-caller controls and update both owning contracts in this coherent candidate.

Change-source: pulse-maintainer
2026-10-12 18:02:24 +01:00
pulse-triage[bot] c253560830 Integrate reviewed DSM Upstart removal safety
Preserve Delivery's complete exact candidate and retained source-p77gpfj5 evidence. Native DSM and whole-agent removal acceptance remain separate.

Change-source: pulse-maintainer
2026-10-12 17:14:17 +01:00
rcourtman 9c28f097b3 Warm the pulse-agent build before the pinned release API shards
The first beta's release workflow failed twice in backend_tests:
TestHostAgentCredentialFileHandoff, added on 2026-10-11 and so new to
every release job, compiles pulse-agent itself and was killed at exactly
180s with "build agent from this source: signal: killed".

The release runner starts each API shard with a small pinned GOMAXPROCS,
and the test's child compiler inherits it. A cold agent build is about
250 CPU-seconds, so under the pin it serializes past the test's fixed
three-minute limit. The release job also has no Go build cache, and the
race-enabled test binary the runner compiles does not warm this plain
build. Pull request jobs keep a warm cache, which is why the test passed
there.

Reproduced on pulse-dev with the shard's conditions, a prebuilt test
binary, GOMAXPROCS=1 and an empty cache: the test fails at 180.02s with
the identical message. With the agent built once beforehand, unpinned, in
99s, the same pinned run passes in 16s.

Build the agent once in the runner, after compiling the test binary and
before any shard starts, with the full CPU count. The runner test pins
that order so the warm-up cannot drift after the shards, and the contract
records why. Against the previous runner the pin fails with the expected
message. The release preflight and policy suites pass.

Contract-Neutral: Release test runner ordering only; no published artifact, tag, signing, install or customer contract changes.
2026-10-12 16:28:14 +01:00
pulse-triage[bot] 247d39af39 Keep guest readings current and preserve recovery during agent removal (#2872)
## What changed and why
Keep Proxmox guest readings, alerts and History owned by the live
connection that collected them. A completed obsolete poll must not
republish after connection replacement, retirement or runtime shutdown.
Both enumeration routes now stage the complete guest generation and its
effects before publication. Caller detail-budget expiry still preserves
already collected inventory, without granting another read or fallback.

Make FreeBSD rc.d and SysV agent removal retain recovery material until
shutdown, process absence and disabled boot activation are confirmed.
Refused, incomplete or ambiguous observations stop removal; a partially
stopped installation is not automatically restarted. Existing
systemd/OpenRC protections remain.

Keep the guest memory explanation's agent-setup advice safe: defer
setup, restarts and live guest-agent probes during backups or an
incident. The underlying percentage, source and reading age are
unchanged.

These are bounded maintenance steps for reported workload safety,
restart recovery and safe removal, not whole-report completion. Related
to #1099, #2439, #2619, #2762 and #2822. Native recovery, independent
thaw, Windows removal and installed acceptance remain separate.

## Included source
Complete unpublished range:
`dba4b722af3f1e9a648b09ace9484a1cfc26f785..d4e89c1a1bd7892b3fc16441365a90a15139efd4`.
- Guest publication candidate:
`1ccc3651fdd611a1d5da47c5d44659fbcd4c2773` through
`08a7eaf70d8452c223e05b19ce2bd7866bbb237d`, integrated at
`ac00b9ec782b1a5964c3a9b00cdd19775293d6fc`.
- Recovery-preserving removal candidate:
`bad484550830d19569e0332c96c495e71c1694d6` through
`65f813c49758c663380ad0179e5cce3245615baf`, integrated at
`7bda196005275cd25da63776db8eadc500c0066d`.
- Memory setup precaution: `c776990b817b6a96d02abc38692960c2be578419`
and compatibility-fixture correction
`9327bc02409ffe3f07d14b8f560d6fb75d492f46`, integrated at starting
reviewed tip `020a7be6bf2a2923c291395a8409ed79ddcde336`.
- Additive upstream composition
`b523c0b6f33b6cc0ddcb36b967b05fffa7f63b4a` contains the published backup
guide unchanged. It has the same source tree as the starting reviewed
tip. Every accepted commit identity and ancestry is preserved.

- Additive correction `6281d6e0008aec029b5cc7f79820ed46159aa17a`
reconciles the canonical Docker-ingest source guard with both routes
through the ownership gate, retaining the canonical state-update
assertion and all behavioral withdrawal controls. It changes no runtime
source.

- Additive upstream composition
`a61f14c823be5ee99f20b2aa2eb3808eff83645d` incorporates the published
second-beta metadata-test repair at
`171f003a04950b53e577019398961758eb32d91c`. Its exact object was already
present; no transport or history rewrite was needed.

- Final additive composition `d4e89c1a1bd7892b3fc16441365a90a15139efd4`
incorporates published beta.2 metadata at
`dba4b722af3f1e9a648b09ace9484a1cfc26f785`. The bounded upstream refresh
completed at the requested identity with source unchanged before this
merge. It adds no new maintenance scope or release action.

## Validation and limits
Publication provenance, whitespace and all fifteen per-commit completion
guards pass. The complete-range browser guard validates the unchanged
source-bound memory precaution receipt. Recorded candidate evidence
includes 33 guest scenarios and both original 500-guest budget controls,
60 removal methods and ten targeted installer fixtures, and 40 grouped
browser checks with twelve captures recorded as inspected. Unchanged
sufficient browser evidence was not replayed merely for batching.
Earlier Go 1.26.8 results remain diagnostic rather than matching the
declared compiler.

- `source-ji6j004_` on the first composition observed Go 1.26.9 and
failed the stale direct-publication assertion. The complete failure
remains retained; later vet/installer steps were not reached.
- Corrected `source-krkur1bl` on
`6281d6e0008aec029b5cc7f79820ed46159aa17a` passes the targeted
Proxmox/guest-ownership race suite, monitoring vet, shell syntax and
twelve targeted installer/consumer tests, including fifty Python removal
controls executed through their production-function wrappers. It uses Go
1.26.9, exits zero, collects complete output and confirms guest stop.
These monitoring and agent-removal bytes are unchanged in the final
composition.
- `source-9u5ig0nx` passes 62 frontend tests, full types, changed-source
formatting/ESLint, the production/embed build and every bundle budget.
Exit zero, complete output and guest stop are recorded. The final
frontend delta from that proof is only the already-published
upgrade-guide mirror; JavaScript, styles, manifests and browser-verified
inputs are unchanged.
- `source-p3ht5oy2` verifies the reconciled canonical ingest guard and
the newly published prerelease-predecessor helper/current prerelease
metadata on `a61f14c823be5ee99f20b2aa2eb3808eff83645d`. Two
stable-packet checks correctly skip on prerelease source. Go 1.26.9,
zero exit, complete output and guest stop are recorded. The later beta.2
metadata is validated separately on the final tip.
- Exact final `source-sl4t8d7o` on
`d4e89c1a1bd7892b3fc16441365a90a15139efd4` passes shell syntax and the
prerelease-predecessor/current beta.2 install-metadata checks on Go
1.26.9. The two stable-packet checks remain explicitly skipped. Exit
zero, complete 1,485-byte output and completed guest stop are recorded.
Earlier receipts retain their reporting-line-bound flags without loss of
their complete raw output.

These checks do not establish installed restoration, native guest
safety, Docker qualification, release readiness or publication of this
maintenance. Administrative review and all required exact-head hosted
checks still govern landing; any advisory failures need an
evidence-based disposition.


[How Pulse handles
triage](https://github.com/rcourtman/Pulse/blob/main/docs/AI_TRANSPARENCY.md)
2026-10-12 14:30:53 +00:00
pulse-triage[bot] da597d34d6 Give DSM manual temporaries to the existing installer EXIT cleanup
Inline and command-double changes did not establish cleanup on the retained race refusal. Register only the non-credential manual temporary with the existing installer trap and execute that exact trap in the confined caller controls. Never register the credential-bearing staged job backup for automatic deletion. All retention, no-clobber, refusal and native obligations remain intact.

Change-source: pulse-maintainer
2026-10-12 15:15:09 +01:00
pulse-triage[bot] b7b0eb0b01 Handle each DSM override failure before owned temporary cleanup
The retained race refusals still left manual temporary files after the command-double change. Check write, permission and atomic link operations individually rather than relying on the grouped chain to reach cleanup. Keep concurrent files/directories and all credentials intact; the same mandatory race assertions remain. Matching Go1.26.9 is now actually observed and the complete installer suite remains required.

Change-source: pulse-maintainer
2026-10-12 15:00:47 +01:00
pulse-triage[bot] dc678bfd9d Preserve refused link exits through the confined DSM command double
The two race controls retained private manual temporary files because the command double exited before the production failure handler. Exact confined traces show that exit boundary. Capture and return the real external ln exit explicitly, preserving production cleanup and every file/directory race assertion. No product code, safety assertion, method count or deadline changes.

Contract-Neutral: Faithful closed-model external exit observation only; no runtime or contract delta.
Change-source: pulse-maintainer
2026-10-12 14:52:56 +01:00
rcourtman 4337c2767f Restore Patrol's Safe auto-fix and Autopilot modes (#2871)
Reverts #2863 before any release ships it. No tag contains it;
v6.6.0-beta.1 predates it.

The live Pro pricing and Patrol pages, in English, German and Spanish,
sell both modes: Pro "applies safe fixes in the mode you choose (Ask
first, Safe auto-fix, or Autopilot)". Paying installs also chose them.
Shipping the retirement would have silently downgraded those installs
while the sales page still promised the modes. If the modes are retired,
that needs a dated notice: stop selling them, warn affected installs
in-app, then re-ship the change.

The companion enterprise revert (rcourtman/pulse-enterprise#114) already
landed. It is safe with either core.

The receipt #2863 landed stays in place; this adds a receipt for the
restored content.

Verification:
- Go vet is clean. config, ai, ai/qualification, telemetry,
actionlifecycle, unifiedresources, aicontracts, pkg/server and api pass
on pulse-dev. The only api failure, the server-info development check,
needs `.git` in the tree.
- Release_control Python suites, the commit guard, the status and
registry audits, and the docs mirror all pass.
- Browser, on a pulse-enterprise build of this revert with a Pro
licence:
  - all four Patrol modes are offered and Safe auto-fix saves;
- the Autopilot acknowledgement dialog activates effective `full`, and
Revoke is shown;
  - drawer and plan page render, and phone width is fine.
2026-10-12 14:44:07 +01:00
pulse-triage[bot] d4e89c1a1b Compose published beta metadata without changing reviewed maintenance
Change-source: pulse-maintainer
2026-10-12 14:38:58 +01:00
pulse-triage[bot] f472758a37 Observe previous DSM link arguments before judging the restore race
The retained fourth proof stopped at a test-double argument refusal before the intended prior-source race. Execute both legitimate ln argv forms unchanged inside the private fixture; current file/directory preservation still requires exact-target non-clobbering semantics. No product change, safety assertion, method count or deadline is weakened.

Contract-Neutral: Transparent closed-model command arguments only; no runtime or contract delta.
Change-source: pulse-maintainer
2026-10-12 14:23:37 +01:00
pulse-triage[bot] a61f14c823 Compose current prerelease metadata repair with reviewed maintenance
Change-source: pulse-maintainer
2026-10-12 14:22:47 +01:00
pulse-triage[bot] e24bfa79af Exercise concurrent DSM targets inside the actual restore operation
Extend the existing no-clobber method with file and directory creation at restoration, not only before its initial path check. The real private-file operations must retain the original staged inode and every credential, never overwrite or write inside a concurrent target. Product code, method count, deadlines and native obligations are unchanged.

Contract-Neutral: Closed-model race coverage only; no runtime or contract delta.
Change-source: pulse-maintainer
2026-10-12 14:14:17 +01:00
rcourtman 8cff7de026 Restore Patrol's Safe auto-fix and Autopilot modes
Reverts #2863 before any release ships it. The live Pro pricing and
Patrol pages, in English, German and Spanish, sell both modes ("applies
safe fixes in the mode you choose: Ask first, Safe auto-fix, or
Autopilot"), and paying installs chose them. Shipping the retirement
would have silently downgraded those installs while the sales page still
promised the modes.

If the modes are retired, that needs a dated notice: stop selling them
first, warn installs on those modes in-app, and then re-ship the change.
It should not arrive through an engineering cleanup.

The receipt #2863 landed stays in place; this commit adds the receipt
for the restored content.
2026-10-12 14:13:47 +01:00
pulse-triage[bot] a7271f5840 Keep DSM config restoration atomically non-clobbering
A pathname absence check followed by mv could overwrite a concurrent root-created job. Use exact-target non-replacement links for override creation and config restoration; directory races also refuse without creating nested artifacts. Confined concurrent-file/directory controls are mandatory. Partial activation is never restarted and conflicting staged recovery is never discarded.

Change-source: pulse-maintainer
2026-10-12 14:11:23 +01:00
pulse-triage[bot] dae9cb86bd Prepare v6.6.0-beta.2
Beta cut from main at 171f003a04. It carries every change merged since stable v6.5.0.

Contract-Neutral: Release-only v6.6.0-beta.2 version, release notes and distribution metadata; no public install or runtime contract changes.
Change-source: pulse-maintainer
2026-10-12 14:10:58 +01:00
pulse-triage[bot] adcc223f55 Bind DSM controls to the actual missing tool and uninstall section
The first exact proof retained two fixture failures: timeout executes an external initctl rather than a shell function, and the source-order assertion unintentionally included later install code. Remove the actual model binary for its missing-tool control and bound the assertion to uninstall. Add an explicit concurrent-config/no-clobber recovery verdict; product code and safety deadlines are unchanged.

Change-source: pulse-maintainer
2026-10-12 13:59:31 +01:00
pulse-triage[bot] a6527d9ae3 Confirm DSM Upstart retirement before erasing agent recovery
Treat DSM6 Upstart and stale DSM7 jobs through their actual manager, not SysV or late best-effort cleanup. Keep trusted job state and credentials on refused, unknown or partial observations; require effective manual activation and observed stopped/absent processes before remote removal and local erasure. Stage the original config until absence is confirmed, restore without restart on failure, and preserve non-clobbering recovery. Mandatory production-function/caller controls retain every refusal and timeout boundary. This is confined source repair, not native Linux/Windows or whole-issue acceptance.

Change-source: pulse-maintainer
2026-10-12 13:55:32 +01:00
rcourtman 7673e8bc10 Teach the pre-release metadata test about a second beta
The second beta's preparation pull request failed Backend tests
(TestCurrentPrereleasePacketTracksInstallMetadata): the changelog the
release metadata tool wrote said it describes the changes since
v6.6.0-beta.1, and the test expected v6.5.0. previousPrereleaseVersion
only understood -rc.N, so for beta.2 it reported no predecessor and the
test fell back to the previous stable. The tool names the predecessor in
the pre-release's own stage, alpha, beta or rc, N-1.

Do the same in the helper: rc.2 follows rc.1 and beta.2 follows beta.1,
while the first of a stage has no predecessor even when an earlier stage
shipped. Pin it with a table test, because beta.1 passed without ever
exercising the second-beta case.

Run against the beta.2 preparation snapshot with this change, the whole
installer test package and the release policy suite pass.

Contract-Neutral: Test helper only; no release, install or customer contract changes.
2026-10-12 13:48:03 +01:00
pulse-triage[bot] 7bda196005 Integrate reviewed recovery-preserving rc.d and SysV removal
Change-source: pulse-maintainer
2026-10-12 13:36:44 +01:00
rcourtman 339539a0ca Retry registry reads when verifying release container images (#2866)
The first beta's release workflow failed in publish_docker at "Verify
exact tags and signed provenance": gh attestation verify copied an image
blob from Docker Hub and got a 502 Bad Gateway. The verifier calls
docker buildx imagetools inspect and gh attestation verify against
Docker Hub and GHCR with no tolerance for a transient registry error, so
one 5xx fails the whole release, and the train can rerun it only once.

Each of those reads is now retried up to four times with doubling
backoff from 10 seconds. They are idempotent, and a moved tag or an
invalid attestation fails identically on every attempt, so a real
failure is delayed by the backoff and never masked. The script's stdout
is the step output, so each attempt's stdout is captured and only the
successful attempt's is emitted: a failed read that printed half a
manifest cannot corrupt the verified digests. VERIFY_REGISTRY_ATTEMPTS
and VERIFY_REGISTRY_WAIT_SECONDS tune it, validated as small whole
numbers so the retry stays bounded.

Tests use doubles that fail like a dropped connection: transient
attestation reads are retried and only the digest proof is emitted; a
digest read that prints a partial manifest before failing leaves no
trace in the output; an exhausted attempt budget fails with an explicit
error and no output; unbounded settings are rejected. The old assertion
that an unverifiable attestation costs exactly one read now expects the
four attempts. Against the previous script the new tests fail. The
contract records the retry.

Checked: all 9 tests in the verifier's test file pass; the script and
its test are not registered in a subsystem, so the completion guard has
no proof file to require.

Second of the release-path retries after #2862 (release listing 504).
2026-10-12 13:04:12 +01:00
rcourtman db57faf1c0 Retire Patrol's Safe auto-fix and Autopilot modes (#2863)
Patrol now has two modes: **Watch only** reports findings, and **Ask
first** investigates and proposes fixes. Every fix waits in Actions for
an operator to approve and run it. Safe auto-fix (`assisted`) and
Autopilot (`full`) are retired.

Why: schema-v17 telemetry for the week to 2026-10-11 counts 1 assisted
and 2 full installs out of 612 reporting Patrol, and 4 executed Patrol
actions in 30 days, all on one install. No GitHub issue asks for more
autonomy. Meanwhile the automatic path carried its own policy leases,
acknowledgement store, per-resource allowlist, release gate and Colima
lab. Investigation is what paid installs use, so it stays.

Behaviour
- A saved `assisted`, `full` or `autonomous` level reads as `approval`.
Both autonomy update routes refuse those levels with `400
invalid_autonomy_level`. The acknowledgement routes are gone.
- The core Patrol action broker only plans: `Plan` and `Submit` persist
the plan and return. `TestContract_PatrolActionBrokerOnlyPlans` forbids
execution calls in its source.
- Removed:
- `ExecuteUnderPolicy`, the policy authorization lease, and the policy
execution store methods;
  - Autopilot acknowledgement persistence, its routes and its dialog;
- the per-resource automatic-action allowlist: type, API field and
drawer editor. The store column is written as NULL.
- Kept for compatibility:
- `GetPatrolFullModeUnlocked` stays on the extension contract and
reports false;
- historical action records keep their lease and reason codes decodable,
labelled as retired modes.
- The Patrol inbox no longer has a "continuing without a decision"
bucket: every current issue is an operator decision.

Governance
- RG-06 now proves Patrol never executes without an operator decision
(integration tier).
- RG-02/RG-04 and the RA35/RA39/RA40 proof commands point at surviving
tests. Every `-run` name was checked against `git grep '^func Test'`.
- Pro plan copy, AI docs, privacy telemetry wording and the subsystem
contracts describe the two modes.

Verification
- Go: vet is clean. config, ai, ai/qualification, telemetry,
actionlifecycle, unifiedresources, aicontracts and api pass on
pulse-dev.
- Frontend: type-check and lint are clean; 217 related test files pass.
- Governance: release_control Python suites, status/registry audits and
the docs mirror pass.
- Browser: a pulse-enterprise build of this tree with a Pro licence, run
before and after merging onto main:
  - the Patrol selector has exactly two modes, and each save reads back;
  - retired levels get 400, and the acknowledgement route returns 404;
  - the drawer Manage tab has no allowlist editor and still saves;
  - phone width is fine; the plan page shows no retired modes.
2026-10-12 12:50:34 +01:00
rcourtman b09ba017eb Retry registry reads when verifying release container images
The first beta's release workflow failed in publish_docker at "Verify
exact tags and signed provenance": gh attestation verify copied an image
blob from Docker Hub and got a 502 Bad Gateway. The verifier calls
docker buildx imagetools inspect and gh attestation verify against
Docker Hub and GHCR with no tolerance for a transient registry error, so
one 5xx fails the whole release, and the train can rerun it only once.

Retry each of those reads up to four times with doubling backoff from 10
seconds. They are idempotent, and a moved tag or an invalid attestation
fails identically on every attempt, so a real failure is delayed by the
backoff and never masked. This script's stdout is the step output, so
each attempt's stdout is captured and only the successful attempt's is
emitted: a failed read that printed half a manifest cannot corrupt the
verified digests. VERIFY_REGISTRY_ATTEMPTS and VERIFY_REGISTRY_WAIT_SECONDS
tune it, validated as small whole numbers so the retry stays bounded.

Test it with doubles that fail like a dropped connection: transient
attestation reads are retried and only the digest proof is emitted; a
digest read that prints a partial manifest before failing leaves no trace
in the output; and an exhausted attempt budget fails with an explicit
error and no output. The old assertion that an unverifiable attestation
costs exactly one read now expects the four attempts. Against the previous
script the new tests fail. The contract records the retry.

Contract-Neutral: Release verification reliability only; no published artifact, tag, signing, install or customer contract changes.
2026-10-12 12:44:29 +01:00
rcourtman 5991a096cb Retire the obsolete governed worktree workflow
The compound worktree commands still assume pulse/v6 and reserve a lease
in the source checkout that Git does not transfer to the new worktree.
They also use a second claim implementation with different renewal and
expiry rules. No callers remain outside their entrypoints, docs and tests.

Use ordinary Git tools under the current branch policy and the supported
work_claim command in the checkout where the slice runs. Remove the legacy
workflow, its private claim engine and their obsolete advertisements.
2026-10-12 12:18:05 +01:00
rcourtman afc4c9275d Retire Patrol's Safe auto-fix and Autopilot modes
Patrol could run some fixes on its own in two paid modes: assisted (Safe
auto-fix) and full (Autopilot, behind a server-owned acknowledgement).
Schema-v17 telemetry for the week to 2026-10-11 counts 1 assisted and 2
full installs out of 612 reporting Patrol, 4 executed Patrol actions in
30 days, all on one install, and no GitHub request for more autonomy,
while the automatic path carried its own policy leases, acknowledgement
store, per-resource allowlist, release gate and Colima lab. Investigation
is what paid installs use, so it stays.

Patrol now has two modes. Watch only reports findings. Ask first
investigates and proposes fixes, and every fix waits in Actions for an
operator to approve and run it.

- A saved assisted, full or autonomous level reads as approval, and the
  update routes refuse those levels with 400 invalid_autonomy_level.
- The core Patrol action broker only plans: Plan and Submit persist the
  plan and return. ExecuteUnderPolicy, the policy authorization lease,
  the policy admission store methods, the Autopilot acknowledgement
  persistence, routes and dialog, and the per-resource automatic-action
  allowlist (store column now written as NULL) are gone.
  GetPatrolFullModeUnlocked stays on the extension contract and reports
  false.
- Historical action records keep their policy lease and tenant/resource
  reason codes decodable, labelled as retired modes.
- The Patrol inbox no longer splits issues into "continuing without a
  decision"; every current issue is an operator decision.
- Release gate RG-06 now proves Patrol never executes without an operator
  decision (integration tier) instead of limited unattended autonomy,
  and RG-02/RG-04 point at the surviving human-admission proofs.
- Pro plan copy, AI docs, privacy telemetry wording and the subsystem
  contracts describe the two modes.
2026-10-12 11:52:11 +01:00
rcourtman d897fc52ce Retry the release listing so a GitHub 504 cannot fail a release
The first beta's release workflow failed in create_release at "Locate
existing release". That step reads up to 100 releases with every asset,
about 25 MB, in one call, and GitHub answered it with an HTTP 504. The
step has no pipefail, so the failed read reached jq as empty input and
the job ended with exit code 5. Timing the call from a workstation, one
of three tries returned an error body, so this is not rare.

Retry the read up to five times with the same backoff the asset upload
uses, and accept only a complete listing of valid pages. A failed or
truncated read must never look like "no existing release": that answer
would stage a duplicate draft for a tag that already has one. Exhausting
the attempts fails the job with an explicit error. The listing call and
the downstream handling of an existing draft are unchanged.

Run the real step script in the release policy test against doubles for
gh and sleep: two 504s then a complete listing finds the draft after
backoff of 15s and 30s; a read that exits 0 but is truncated every time
fails after five attempts, with the capped backoff and no outputs; and a
complete listing without the tag still means no existing release. Against
the previous step the test fails with the production symptom, exit 5 and
the 504 message. The create-release pin list and the contract record the
retry.

Contract-Neutral: Release workflow reliability only; no published artifact, tag, signing, install or customer contract changes.
2026-10-12 11:27:09 +01:00
pulse-triage[bot] 65f813c497 Keep bounded legacy fixture observations atomic
The retained validation ended with an empty model record, not a product erasure verdict. Use atomic replacement for closed model updates so command interruption cannot truncate the state used to judge actual recovery files; production deadlines and safety assertions are unchanged.

Contract-Neutral: Closed fixture observation writes only; no product runtime or contract change.
Change-source: pulse-maintainer
2026-10-12 10:24:58 +01:00
pulse-triage[bot] ac4c4cebe4 Preserve first service-inventory evidence with upstream fresh-host repair
Compose upstream bed5052eb5 without replacing reviewed history. Keep the accepted one complete stdout/stderr observation and blank-line refusal instead of upstream second-sample replacement. Retain upstream real-systemctl fresh-host assertions and its platform-availability decorator alongside every reviewed failure-retention control. No release, installed recovery or LXC stop-cause claim.

Change-source: pulse-maintainer
2026-10-12 10:15:52 +01:00
pulse-triage[bot] e1b3a352c5 Preserve truthful partial-stop recovery in legacy controls
An owned activation link may already be disabled before a later observation fails; assert exact service/PID/credential retention without re-enabling it. Require the old installed-script PID-erasure adverse control, keeping that runtime observation distinct from credential erasure and new renderer behaviour.

Contract-Neutral: Verification and precise contract documentation only; the production installer is unchanged.
Change-source: pulse-maintainer
2026-10-12 10:15:03 +01:00
pulse-triage[bot] 6d654f3984 Bind complete rc.d renderer in removal controls
The renderer contains nested functions inside its heredoc; extracting at the first closing brace never exercises its stop function. Bind its full top-level body and inject missing sysrc in the executable model reached by timeout.

Contract-Neutral: Confined test extraction and missing-tool modelling only; no installer or contract behaviour changes.
Change-source: pulse-maintainer
2026-10-12 10:09:43 +01:00
rcourtman bed5052eb5 Treat no matching unit files as an empty service inventory (#2859)
The first beta (v6.6.0-beta.1) now passes its preparation checks and
both source pairs, and its release workflow failed twice at the
install.sh smoke test: on a clean Debian 12 container install.sh stops
with "Cannot identify the Pulse systemd service: unit inventory failed".
That is a real regression on main, not a flake. v6.5.0 does not have it,
so no release carries it.

Cause: the 2026-10-10 service discovery change reads `systemctl
list-unit-files -- pulse-backend.service pulse.service` and refuses on
any non-zero exit. systemd exits 1, printing nothing on stdout or
stderr, when none of the named unit files exist, which is every fresh
host (checked on systemd 255 here and by the smoke container's systemd
252). The change's comment says a successful empty read permits a new
installation, but an empty read is not exit 0.

Why the tests missed it: their systemctl double reports no units as exit
0, and `test_partial_failed_inventory_is_not_absence` asserted that an
empty inventory with exit 1 is refused.

Fix: one shared inventory read, used by the installer, the unattended
updater and the auto-update mask check (which had the same hazard). It
accepts exactly the silent exit 1 as an empty inventory, after a second
read confirms there is still no output and no message. A timeout, a
signal, any other status, or an exit 1 that carries output or a message
stays a failed inventory, so real failures still refuse.

Tests: the doubles now model systemd (a failure prints its message, a
silent exit 1 is absence), the two tests that encoded the defect model a
real failure, and new tests cover a fresh host for both scripts,
including real `systemctl --root` over an empty unit root. Contract doc
updated. The registered runtime proofs for install.sh and the unattended
updater (the Go tests that drive this suite) now require the fresh-host
controls to have run and passed.

Checked on pulse-dev: against the unfixed scripts the four new
fresh-host tests fail and the rest pass; against this change all 18
discovery tests, the 2 repair tests and the 16 timer tests pass, and the
Go installer tests pass (184 s).

This replaces #2855, whose first commit lacked the registered proof
files the completion guard requires per commit.

Refs #2785
2026-10-12 10:07:19 +01:00
pulse-triage[bot] 123652e29b Preserve reviewed monitoring repairs with upstream Discovery removal
Compose current main e2f4bdff03 additively. Retain both subsystem records and the held change-age control while withdrawing only the obsolete Discovery identification test. Reviewed identities and ancestry, canonical guest History ownership and upstream feature removal remain intact.

Change-source: pulse-maintainer
2026-10-12 10:04:58 +01:00
pulse-triage[bot] c3911ea59f Bound legacy removal PID records and required-tool refusal
Retain recovery before unknown or unavailable timeout/sysrc observations, require bounded PID records, and align the existing daemon-supervisor assertion with checked signal delivery rather than ignored errors. Every source control remains mandatory.

Change-source: pulse-maintainer
2026-10-12 10:04:52 +01:00
pulse-triage[bot] bad4845508 Retain rc.d and SysV recovery until removal is observed
Continue #1099: stop and disable the actual legacy manager before remote deregistration or local erasure, recheck after confirmation, and retain PID/service/credential material on refusal or unknown state. Check collector and supervisor absence, exact runlevel ownership and rendered signal failures with confined production-function controls. Appliance bootstrap and native acceptance remain separate.

Change-source: pulse-maintainer
2026-10-12 10:00:09 +01:00
pulse-triage[bot] 14518f6f3a Integrate reviewed safety fixture alignment
Preserve exact Delivery candidate ce1a28f64d. Review confirms fixture-only intake, private-file guidance, native helper and bounded teardown corrections retain safety controls. Retained source-60krqmze proves controlled fixtures; Go 1.26.9 and native macOS containing CI remain distinct from its Go 1.26.8 diagnostics.

Change-source: pulse-maintainer
2026-10-12 09:43:52 +01:00
rcourtman 3e3ad9a5bd Keep the real-systemctl controls skipped where systemctl is absent
The previous commit inserted a new real-systemctl test above the old one
and took over its skipUnless decorator, so on macOS, which has no
systemctl, the new test skipped and the old one ran unprotected and
failed. Restore the decorator on the old test.

The installer proof required the real-systemctl control to have passed.
Where systemctl does not exist it must instead report skipped, so the
proof now checks for ok on a host with systemctl and for skipped on one
without, and still fails if the control is absent from the output.

Refs: #2785
2026-10-12 09:40:57 +01:00