Check the single root/sudo argv body rather than the obsolete duplicated command spelling. Retain credential-file, scope and cleanup assertions, and record fixed-field signal delivery and terminal facts to distinguish the observed BusyBox hangup from a missed fixture signal. Runtime commands are unchanged; the original hangup remains adverse until executed cause and cleanup evidence settle it.
Contract-Neutral: Test-only privilege dispatch assertions and bounded signal observations; no producer, API, trust or credential contract change.
Change-source: pulse-maintainer
Preserve accepted 0efe3f7a12 and exact upstream ebfdc9d669 additively. Keep quiet unavailable captions, keyboard and touch reading explanations, stopped-agent provenance and primary CPU readings. Preserve stable denied-update help outside Details and all regression assertions.
Change-source: pulse-maintainer
Three rules chose a node's single CPU temperature. Node history took
CPUMax first, agent history took cpu_package first, and the node drawer
recomputed the maximum of package, CPUMax and every core in the
browser. On an agent-fed node CPUMax is built from cores alone and can
sit below the package, and elsewhere a core can run above the package,
so the drawer's CPU temperature headline could disagree with the line
drawn beneath it and with the History tab. Node alerts and the CPU
low/record tracking used yet another package-first rule.
models.PrimaryCPUTemperatureCelsius is now the one rule: the hottest
usable package, CPU-maximum or core reading, with a sensor-map form for
agents. Node and agent history, the router's live fallbacks, the
unified resource temperature, node temperature alerts and the CPU
low/record tracking all call it. The drawer reads the resource value
through a new Node.cpuTemperature field instead of recomputing it, and
getCpuTemperature is removed.
Mock mode wrote a second package reading under a cpu.package key into
every agent host, including node-linked ones, from a series unrelated
to the node's static reading. A node and its linked agent now carry one
reading, sampled from the agent's series under the agent's real keys,
and both histories seed from that series, so the current reading
continues the line.
Record the actual privileged Bash reader from the selected tool and send HUP/TERM to it while retaining the controlling terminal. Whole-session termination cannot supply the same restoration observation. Keep the adverse whole-group result, full mode/privacy assertions and every caller control.
Change-source: pulse-maintainer
Non-interactive PTY sessions dispatch through sh while history sessions use bash. Supply both in the closed PATH so tool/mode controls exercise the producer rather than failing at child creation; retain all privacy and complete-terminal assertions. Preserve the observed failed suite.
Change-source: pulse-maintainer
Mirror the qualified Unix reader in setup, Proxmox and container producers: select one terminal tool, distinguish missing terminal/tool/mode failures, restore its complete state before installation and on cleanup, and retain silent overflow draining. Emit the isolated privileged body once without changing tokens, trust, scopes, profiles or state. Cover serialized contracts and actual consumer payloads.
Change-source: pulse-maintainer
Cover setup, Proxmox and container callers with a real PTY, isolated standalone and BusyBox tool selection, distinct fail-closed modes, private root/sudo history and one bounded command body. These controls expose the unchanged backend reader before its repair.
Change-source: pulse-maintainer
Preserve exact reviewed d636bfdaea and published 0a44d276db ancestry. Retain both contract additions, readable System evidence and stable accessible update help alongside upstream alert-first trends, facts and Details.
Change-source: pulse-maintainer
Patrol's operator-state projection dereferenced the one-shot
MaintenanceStartAt/EndAt whenever IsInMaintenanceAt was true. A
recurring window also reports active but leaves those fields nil, so
the first finding Patrol evaluated during a recurring occurrence
panicked the provider. The projection now takes its bounds from the
active occurrence.
Alerts already silence guests under a host window scoped to
resource_and_descendants, but Patrol read only the exact resource, so
the same planned work dismissed a guest's alerts and still raised its
Patrol findings. Both now resolve maintenance through one rule,
unifiedresources.ActiveMaintenanceCoverageAt: own window plus
descendant-scoped ancestor windows, latest active end wins. Only
maintenance is inherited; monitoring mode, lifecycle and remediation
locks stay exact-resource state. An inherited dismissal says the window
is on a parent resource and names it on the lifecycle event, and the
Manage help now says descendants' new Patrol findings are dismissed
too.
The advisory Benchmarks check failed #2884 on NormalizeRoute/with_uuid
alone, +12.25% (p=0.000), though that PR changed only AI handler code.
It was not the only one. Since the bounded route scanner landed on
9 October (01788459f1), normalizeRoute takes 30-180ns a path on CI runners. In 72
paired CI comparisons that measured internal/api from then until 13
October, the BenchmarkNormalizeRoute rows and their parallel variant
failed the gate 17 times. None of those PRs touched route code, and 6
of the 17 failures did not involve with_uuid: deep_path_truncated,
with_query_params, metrics_history, with_numeric_id and Parallel each
crossed 10% too. with_uuid moved past 10% in 21 of the 72 comparisons,
in both directions.
This is the same layout effect that retired the "/" fast path (#2255)
and NormalizeSegment (#2258). Go aligns functions to 32 bytes, so code
added earlier in the package moves normalizeRoute between the halves of
a 64-byte block. That changes its loops by a cycle per iteration. Every
path shares those loops, so retiring with_uuid alone would leave the
other rows failing. Summed over all six paths, a mixed-path row would
still have moved up to 10%.
BenchmarkNormalizeRoute and BenchmarkNormalizeRoute_Parallel are
removed. Their allocation columns never varied, and they are now pinned
by TestNormalizeRoute_LabelAllocationProfile. For each former path it
requires exactly one allocation, of the same size as a fresh copy of the
label. It runs in the existing isolated child process and takes the
lowest of three windows, so one stray runtime allocation cannot fail it.
BenchmarkFullMiddlewarePath still times the normaliser inside the
request path, with a CI maximum of +8.4% over those 72 runs, and
BenchmarkNormalizeRoute_DiscardedSuffix still times a long discarded
suffix. Gross classification slowdowns are left to those rows: a
doubled UUID scan has no deterministic signal, and the retired row
could not separate one from layout.
Proofs, on pulse-dev with the CI runner narrowed to ./internal/api/ at
30 samples. The probe is an unrelated init-time function in a file
sorted before http_metrics.go. It moves normalizeRoute from 32 to 0 mod
64 in the test binary without changing its size:
- old tree vs old tree plus probe: with_uuid -14.70% (p=0.001). Read the
other way, as a PR that removes the probe, the gate exits 1 on
NormalizeRoute/with_uuid alone, +17.23% (p=0.001). That is #2884's
shape.
- new tree vs new tree plus probe: gate exits 0 in both directions. On
a first run under load 9-15, three millisecond-scale rows that run no
route code flagged at p=0.025-0.046 with spreads of 15-38%. The
repeat came back clean in both directions.
- mutation controls on the final test: sizing the label buffer at twice
the label fails only the new test. The existing at-most-one-allocation
test passes it. Joining the label through an intermediate fails both.
- the route tests pass 20 times plain and 10 times under -race.
Preserve the complete reviewed maintenance tip and current published Pro Patrol default. Retain both independent agent-lifecycle contract additions when resolving their shared insertion point; no runtime change is introduced by the resolution.
Change-source: pulse-maintainer
Pro sells Patrol investigation, but every install starts in Watch only
and stays there unless the operator finds the mode control. In the paid
telemetry read on 12 October, 20 of 35 Pro installs with Patrol on ran
Watch only, and none of those 20 ran an investigation in 30 days, so
the feature they paid for never ran.
An install that never saved a Patrol mode now runs Ask first when it
holds a positive investigation licence. Patrol investigates new and
re-detected warning and critical findings and proposes a fix; nothing
changes without approval. The default only applies to a positive
licence answer: a missing licence checker counts as unlicensed, so a
startup window cannot spend provider budget on a free install. Free
installs and explicit choices are unchanged.
The Patrol header says so once, with the cost (the operator's AI
provider and 30-day budget) and two actions that save Ask first or
Watch only. The notice never renders on a plan-locked install. The
header also stops claiming "Watching your infrastructure" while Patrol
cannot run yet and reads "Patrol is not running yet" instead.
Omit mobile connection and push offers, and advertise only current Pro history. Same-path HTTP controls preserve signed grants, public/private runtime fences and 7/14/90-day compatibility without changing subscriber terms.
Change-source: pulse-maintainer
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.
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.
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
AI Discovery ran a separate model-backed service scanner beside Patrol
and the Assistant: its own store, scheduler, model route, API, tool and
drawer UI. No telemetry counter ever measured its use (the telemetry
discovery_enabled flag OR'd it with network subnet discovery), the
maintainer judged it a flop, and the context it produced is already
available to the models through pulse_query, pulse_read and the
unified-resource context sections.
This deletes internal/servicediscovery, internal/ai/infradiscovery, the
pulse_discovery tool, the /api/discovery routes, the mock Discovery
fixtures, the Discovery tabs in the resource, guest, node and Docker host
drawers, the identified-service cards, readiness badges, provenance
markers, suggested web-interface URLs, the Workloads AI Context column,
the chat "Discovery is off" hint and the AI Service Context settings page.
The old settings route redirects to Assistant settings. The model-bound
sanitizer allow-list existed only to pass Discovery context through, so it
goes too, along with the CopyableCodeRow primitive that only the
Discovery tab used.
Network subnet discovery (/api/discover, the Infrastructure discovery
settings) and the discoveryTarget agent coordinates are separate features
and stay. Stored discovery_enabled, discovery_interval_hours and
discovery_model AI settings are ignored on load; the settings API decoder
is lenient, so older frontends saving those fields still succeed.
Preserve every accepted maintenance commit while incorporating human-authored diagnostics token visibility. Resolve API guide overlap by retaining the shared ai:execute narration gate, explicit deterministic fallback and CSV refusal in both mirrors.
Change-source: pulse-maintainer
/api/diagnostics is readable with settings:read and lists the whole token
inventory: every token's ID, name, timestamps, key hint and which agents
use it, across organizations. A token bound to one organization could
read the other organizations' credential metadata, which the token
management endpoints already refuse to show it.
The diagnostics result is computed once per organization scope and cached
for every caller, so the filter runs after the cache: an API-token caller
that is not instance-wide gets an API token section rebuilt over the
tokens callerTokenMayManage allows, with counts, notes and agent usage
computed over that view. Instance-wide tokens and browser sessions get the
full section, and the cache itself still holds the full result.
Tests cover the builder (tokens, counts, usage) and the handler on the
cached path, including that a scoped caller served from the cache does
not change what the next caller sees. Each filter fails when removed.
Contract-Neutral: Behavioural fix that applies the token visibility rule to diagnostics; no new API surface or contract.
Reports are readable with `settings:read`, but a `POST` report can
narrate with the tenant's Pulse Assistant, a paid provider call recorded
in the cost ledger. Any token holding `settings:read` could therefore
spend that budget, while every other AI-spending route needs
`ai:execute`.
An API token now needs `ai:execute` for AI narration, on single-resource
reports and on fleet reports. Without it the report is still produced,
with the deterministic summary and a note explaining why. Browser
sessions and scheduled reports are unchanged, and `GET` keeps narrating
deterministically.
`report_ai_narration_scope_test.go` covers a session, a `settings:read`
token, a token with `monitoring:read` as well, an `ai:execute` token and
a full-access token on both handlers, and fails when either handler
ignores the gate (each handler is covered separately). The existing
contract test for the GET/POST rule still passes.
The API token inventory is global, but only token creation recorded an
organization. Listing, reading, renaming, deleting and rotating a token
looked the target up by ID across every organization and checked scopes
only. A token bound to one organization could therefore see another
organization's tokens, and rotate one to obtain its raw credential,
including an instance-wide full-access token.
A token caller may now manage a token only if every organization the
target is bound to is one the caller is bound to. A target outside the
caller's organizations answers `404`, as if it did not exist, and is
left out of the list. Instance-wide full-access tokens (full access,
bound only to the default organization) keep managing everything, and
browser sessions are unchanged.
An instance-wide token is the most powerful credential, so only an
instance-wide caller may rotate, delete or edit one, or mint one in the
default organization (directly, or by editing a scoped token to full
access). A caller bound to several organizations that includes the
default one is not instance-wide, even though its organizations are a
superset of the target's. Callers without full-access scope are still
refused by the existing scope-containment checks, so the pinned `403`
cases are unchanged.
Tests drive each handler as an organization-bound caller. They cover
list, get, rename, delete and rotate across organizations, the
within-organization and instance-wide cases that must keep working, the
multi-organization escalation edges (rotate, mint, promote), and the
rule as a table. Each check fails when it is removed. The two existing
failures in this package when run locally on macOS (`systemd-analyze`
missing, a dev-mode expectation) also fail on `main`.
Not changed here: `quick-setup` with `force`, config import and the
development first-run reset can still replace the whole token inventory
with `settings:write`, and `/api/diagnostics` lists token metadata
globally.
Retain exact Core commits and scoped normal/race/vet/ARMv7 and trusted-HTTPS process evidence. This independent repair does not establish the Pi reporter cause or installed recovery.
Change-source: pulse-maintainer
docsLinks.test.ts pins the single-report handler's POST branch by source
text. Move the ai:execute check into resolveNarrator, the one place every
report path resolves AI narrators, instead of branching in each handler:
a caller that may not spend AI budget gets no narrator and only the
findings of an already-running AI service, and the resolver that can
construct a tenant AI service is never called. The handlers return to
their previous shape, with the single-report handler adding only the
note that explains why the report was not narrated.
Contract-Neutral: Refactor that places the same scope check at the shared resolver and restores the pinned source shape; no new API surface or contract.
test_agent_auth_docs pins the token-list handler's iteration and DTO
conversion by source text (range r.config.APITokens and
toAPITokenDTO(record)) to prove the inventory lists every record. The
organization filter had switched the loop to an index; iterate by value
again so the pinned shape and the filter both hold.
Contract-Neutral: Refactor that restores the pinned source shape with no change in behaviour.
Keep generation's read scope distinct from the ai:execute permission needed for single-resource and fleet PDF narration. Preserve the bounded PR2836 runtime guard unchanged, mirror the canonical API/MSP help into shipped assets, and record the actual contract including token-triggered versus server-run schedules. Replace the old unconditional-POST source assertion with both method and spending-scope checks, and cross GET with all five caller types. The production Docs browser fixture checks the public guidance on desktop and touch phone without API requests or mutations.
Change-source: pulse-maintainer
The exact PR2836 delta is confined to the single/fleet narration handler and its five-caller regression tests. Preserve that guard unchanged on the current assigned source before aligning its API/MSP help and method/scope proofs.
Contract-Neutral: Composition of the existing AI-spending scope rule for report narration; no additional runtime behaviour or API surface.
Change-source: pulse-maintainer
Incorporate the upstream frontier present at coordination start without re-parenting reviewed source; later upstream reconciliation remains with the publication gate.
Change-source: pulse-maintainer
The real host agent sends gzip reports. Decode only the fixture observer copy, leaving the request bytes and headers unchanged for canonical router authentication and decompression. Document selected-file startup errors and retained enrolment restart semantics.
Change-source: pulse-maintainer
Keep PULSE_TOKEN out of the direct-token flag default. Refuse an unreadable or empty selected file instead of silently borrowing other credentials, while preserving enrolled runtime-token restarts and implicit token-optional startup.
Cover actual flag loading and a synthetic host issuer, private installer-writer, compiled agent and trusted HTTPS lookup/report journey. This repairs an independent source-selection defect; it does not establish the cause or recovery of Discussion #2769.
Change-source: pulse-maintainer
POST /api/security/quick-setup with force=true sets the administrator
username and password and replaces every API token with a full-access
one. With authentication already configured, a token holding only
settings:write could call it, so settings:write was enough to take the
instance over, although the endpoint is documented as needing a
bootstrap token or an authenticated session.
A token caller now needs an instance-wide full-access token (full access,
bound only to the default organization) once the request would change
credentials. The not-forced "already configured" answer is unchanged, and
browser sessions, the bootstrap token and recovery token paths are
untouched.
The two existing force tests that used a settings:write caller are about
persistence rollback and settings preservation, so they now use a
full-access caller. The new tests use a deliberately weak password so a
caller that passes the check is stopped by validation before any
credential or session is written, and they fail when the check is removed.
Contract-Neutral: Behavioural fix that gives credential rotation the authority check regenerate-token and token management already have; no new API surface or contract.
The API token inventory is global, but only token creation recorded an
organization. Listing, reading, renaming, deleting and rotating a token
looked the target up by ID across every organization and checked scopes
only. A token bound to one organization could therefore see another
organization's tokens, and rotate one to obtain its raw credential,
including an instance-wide full-access token.
A token caller may now manage a token only if every organization the
target is bound to is one the caller is bound to. Instance-wide
full-access tokens keep managing everything, and browser sessions are
unchanged. A target outside the caller's organizations answers 404, as if
it did not exist, and is left out of the list.
An instance-wide full-access token is the most powerful credential, so
only an instance-wide caller may rotate, delete or edit one, or mint one
in the default organization (directly, or by editing a scoped token to
full access); a caller bound to several organizations that
includes the default one is not instance-wide, even though its
organizations are a superset of the target's.
Tests drive each handler as an organization-bound caller and fail when
the matching check is removed.
Contract-Neutral: Behavioural fix that applies the organization binding tokens already carry to token management; no new API surface or contract.
Reports are readable with settings:read, but a POST report can narrate
with the tenant's Pulse Assistant, a paid provider call recorded in the
cost ledger. Any token with settings:read could therefore spend that
budget, while every other AI-spending route needs ai:execute.
An API token now needs ai:execute for AI narration, on single-resource
and fleet reports alike. Without it the report is still produced, with
the deterministic summary and a note saying why. Browser sessions and
scheduled reports are unchanged, and GET keeps narrating
deterministically.
Tests cover a session, a settings:read token, a token with monitoring:read
as well, an ai:execute token and a full-access token on both handlers,
and fail when either handler ignores the gate.
Contract-Neutral: Behavioural fix that applies the scope other AI routes already require to report narration; no new API surface or contract.
`POST /api/agents/agent/uninstall` (and `/api/agents/host/uninstall`) is
a collector's self-removal: a token holding `agent:report` removes the
agent that token owns. For any caller that is not a token, the handler
takes the administrative removal path (`RemoveHostAgent`) and deletes
any host agent by ID. The route was only `RequireAuth` plus
`RequireScope(agent:report)`, and browser sessions bypass token scopes,
so a non-admin SSO, proxy or organization-member session could remove
any agent, while the equivalent `unlink` and `DELETE` routes require an
admin.
The route now uses `RequireAdmin` like its neighbours. Token callers are
unchanged: `RequireAdmin` admits them and the `agent:report` scope check
still applies, so the collector's own uninstall and `install.ps1` keep
working (they are the only callers; the frontend does not use this
route).
`TestProxyAuthAdminGatesAdminEndpoints` gains the two uninstall routes
(it fails with the old wrapper: the non-admin request reached the
handler). `agent_uninstall_scope_test.go` keeps the token path reachable
and the scope check in place.
`/api/ai/patrol/attention/` is one prefix for reads, lifecycle mutations
(`acknowledge`, `unacknowledge`, `suppress`, `unsuppress`) and action
planning. Its outer gate used the read-detail scope set
(`monitoring:read`, legacy `ai:execute`, `relay:mobile:access`) for
every method, so a token holding only `monitoring:write` was refused
before the mutation handler's own `monitoring:write` check could run.
The pinned capability inventory (`relay_mobile_capability_test.go`)
already says `POST .../{item_id}/{mutation}` needs `monitoring:write`.
The outer gate now follows `HandleAttention`'s dispatch: a lifecycle
mutation is admitted by the mutation scope set, everything else by the
read set. Behaviour that does not change: a read-only token still cannot
mutate, a write-only token still cannot read, action planning keeps its
read-side gate plus its own entitlement and plan/approve/execute
authorization, and browser sessions bypass scopes as before.
`attention_mutation_scope_test.go` pins each of those four cases and
fails when the mutation routing is reverted.
POST /api/agents/agent/uninstall (and its host alias) is a collector's
self-removal: a token holding agent:report removes the agent that token
owns. For any caller that is not a token, the handler instead takes the
administrative removal path and deletes any host agent by ID. The route
was only RequireAuth plus RequireScope(agent:report), and browser
sessions bypass token scopes, so a non-admin SSO, proxy or organization
member session could remove any agent, while the equivalent unlink and
delete routes require an admin.
The route now uses RequireAdmin like its neighbours. Token callers are
unchanged: RequireAdmin admits them and the agent:report scope check
still applies, so collector and install.ps1 self-uninstall keep working.
The existing non-admin proxy test gains the two uninstall routes, and a
new test keeps the token path reachable and the scope check in place.
Contract-Neutral: Behavioural fix that gives the administrative removal path the admin gate its sibling routes have; no new API surface or contract.
/api/ai/patrol/attention/ is one prefix for reads, lifecycle mutations
(acknowledge, unacknowledge, suppress, unsuppress) and action planning.
Its outer gate used the read-detail scope set for every method, so a
token holding only monitoring:write was refused before the mutation
handler's own monitoring:write check ran. The pinned capability inventory
already says POST .../{item_id}/{mutation} needs monitoring:write.
The outer gate now follows the handler's dispatch: a lifecycle mutation
is admitted by the mutation scope set, everything else by the read set.
Read tokens still cannot mutate, a write-only token still cannot read,
and action planning keeps its read-side gate plus its own authorization.
Contract-Neutral: Behavioural fix that makes the route match its pinned capability inventory; no new API surface or contract.
Two authorization gaps where a token could do more than its scopes allow.
POST /api/security/regenerate-token replaces the whole token inventory,
wildcard tokens included, and issues a full-access credential (nil scopes
normalise to "*"). A token holding only settings:write could therefore
wipe every other token and mint an unrestricted one, which the normal
create and update paths refuse because a caller can only grant scopes it
holds. A token caller now needs full-access scope and must not be bound
to a non-default organization; anything narrower gets 403 and is pointed at
POST /api/security/tokens/{id}/rotate, which replaces one token. Admin
sessions are unchanged.
/api/resources/ is one prefix route gated on monitoring:read, but it also
dispatches POST link, unlink and report-merge, which persist resource
identity changes. A read-only token could change them. Anything other
than GET or HEAD on that prefix now needs monitoring:write; the more
specific registrations (operator-state, maintenance) keep their own gates.
Tests pin both boundaries and each fails when its fix is reverted. Two
existing regenerate tests that used a settings:write caller now use a
full-access one, since their subject is owner inheritance and rollback.
Contract-Neutral: Behavioural fix that enforces the documented token scope model; no new API surface or contract.
The broader API race proof failed after 902 seconds with the oversized ZIP fixture among its unterminated tests; the missing panic output does not establish the cause. The fixture needlessly Deflates 100 MiB of zeros. Generate the same exact oversized entry with ZIP Store and streamed zero input instead, keeping the production cap, stream-limit assertion, archive validity and other Deflate controls unchanged.
Contract-Neutral: Only the ZIP overflow test fixture encoding and construction cost change; the actual oversized entry, runtime extraction policy, size bound, error assertions and test deadlines are unchanged.
Change-source: pulse-maintainer
pulse_control only plans typed resource actions into Pulse Actions
(executeControlResource -> typedActionPlanner). The handlers that sat
behind the retired model-authored command, file and container paths
stayed in the tree with no production caller: run command, guest
control, app-container control, Docker control and container update,
Kubernetes scale/restart/delete-pod/exec, and file append/write.
registerFileTools was never called either, so pulse_file_edit is not
registered at all; calls to it are denied by the mutation registry
before any tool lookup.
A whole-program reachability run over cmd/... lists each of them as
unreachable, and so is everything only they used: approval-record and
preflight authoring, the command and native-action audit lanes with
their remediation-lock gate and plan-hash helpers, the Docker host
resolvers, and the file write verification. The executor's autonomous
flag, whose only readers were those handlers, goes with them (the
executor's SetAutonomousMode and the flag argument of SetContext).
Delete them with their tests and the constants, types and test helpers
they stranded. The contract prose that described the removed broker now
says that plan freshness and the operator remediation lock are enforced
by internal/actionlifecycle. Two source pins that named deleted code go
(the publishActionCompleted dispatch sites and the pulse_file_edit
declaration), the standards tests drop their expectations of an
ActionPlan construction in action_audit.go and of the legacy app_container
rejection in the deleted file-edit test, and the RA35 evidence entry for
the deleted run-command test goes with them.
Left alone on purpose: the saved autonomous control level and its
entitlement and approval-admission checks, which stay as legacy
compatibility, Service.SetAutonomousMode and the chat clamp,
SetOnActionCompleted and its router wiring (no dispatcher is left, the
contract prose says so), and the protected-guests plumbing.
Rebuilt on current main: the first version had 213 commits of drift.
Two conflicts, both on code this change deletes. tools_control.go takes
the deletion over the Protected guests cleanup that landed inside
executeRunCommand. action_audit_remediation_lock_test.go goes with the
audit lanes, including the test added for the dispatch gate's read
through a succession; that gate is deleted here, and
TestLockMovedBySuccessionStillRefusesTheIDThePreviousGenerationLists in
internal/actionlifecycle covers the same refusal on the live path.
Use the existing target-free Monitor fixture for diagnostics uptime and scheduler state; only the test's direct PVE/PBS probes contact its loopback server. Retain the initial nil-runtime failure without weakening production diagnostics or trust assertions.
Contract-Neutral: Tests only; supply the existing required diagnostics runtime without changing production source or diagnostic contracts.
Change-source: pulse-maintainer
Distinguish cancelled or timed-out probes from certificate faults before classifying error text. Replace verification-bypass advice with endpoint, chain and independently verified fingerprint checks across PVE and PBS diagnostics, including scheduler errors and support JSON.
Exercise real loopback trust refusal and operator-supplied pin recovery without changing stored trust, credentials or scheduler authority.
Contract-Neutral: Restore existing TLS/timeout diagnosis and safe recovery guidance; errorKind/schema, saved trust enforcement/settings, agent lifecycle and scheduler/recovery authority remain unchanged.
Change-source: pulse-maintainer
Discriminate advice that weakens certificate trust and stopped handshakes mislabelled as certificate faults, before repairing the existing diagnostic path.
Contract-Neutral: Tests only; no runtime, diagnostic schema or TLS policy change.
Change-source: pulse-maintainer
Replace the copyable guessed stop/run sequence with mounted-data backup and original-deployment recreation guidance. Quote the pull target as one literal shell argument, retaining manual-only and private-image boundaries. Add real-shell controls and a real handler-path check; no Docker daemon or installed recovery claim.
Change-source: pulse-maintainer
The exact normal and race API groups failed at the bare change-password fixture because Basic authentication requires an explicitly configured CSRF store. Give each fixture its own session and CSRF stores and join their workers at cleanup; retain the production fail-closed contract.
Contract-Neutral: Test fixture lifecycle only; production authentication and subsystem contracts are unchanged.
Change-source: pulse-maintainer
Apply saved notification policy before initial resource publication, batch supplemental bindings and retain explicit withdrawals for existing and future tenants. Serialize complete router initialization and refuse old binding collections before ordered writes; preserve admitted alert joins without clearing active alerts. Keep native and demo provider records separated across the mock-switch hook gap.
Contract-Neutral: Internal resource dependency wiring and publication ordering only; existing resource/API schemas, authorization and tenant boundaries, alert thresholds, retention and shutdown policy are unchanged.
Change-source: pulse-maintainer