Commit Graph

241 Commits

Author SHA1 Message Date
pulse-triage[bot] 9188d0f442 Keep capped foreign redirects private and terminal
Check the receiver origin before the unchanged redirect-count limit. Otherwise a same-origin chain that reaches the limit can attach a foreign receiver-controlled Location to a generic retryable error instead of the safe configuration refusal. Cover that branch through direct, enhanced-retry and HTTP Apprise senders; preserve all same-origin limits and scheduling.

Change-source: pulse-maintainer
2026-10-09 23:28:42 +01:00
pulse-triage[bot] aa16ee1d5a Check recovery grouping at its actual admission boundary
Retained full-suite evidence delivered the first recovery after its saved deadline, while the test treated all deliveries observed after emitting fifteen recoveries as early. Measure the receiver time against the first admitted occurrence, preserve the single-group requirement for a burst that fits the unchanged one-second window, and cover late arrivals without sliding that window. Keep ordinary receipt, restart, metadata, suppression, and rate-limit checks; do not change production scheduling.

Change-source: pulse-maintainer
Contract-Neutral: Only correct and strengthen recovery grouping verification; no production grouping, notification, data or access contract changes.
2026-10-09 23:02:09 +01:00
pulse-triage[bot] 7ee035cb6f Keep notification redirects on their configured origin
Do not forward private alert bodies, custom authentication headers or signed requests to a different SSRF-permitted receiver. Keep same-origin redirects and existing TLS/DNS admission, return safe final-URL guidance, and preserve terminal failure and occurrence receipts through both retry layers.

Change-source: pulse-maintainer
2026-10-09 22:33:45 +01:00
pulse-triage[bot] 398eb58938 Keep invalid webhook retry hints out of diagnostic logs
The connected response audit found one remaining receiver-text sink: malformed Retry-After values were copied verbatim into Debug logs. Keep the fixed fallback diagnostic and bounded parsed durations, without retaining invalid header prose. Two regression cases reproduce the leak on the preceding candidate and preserve retry and terminal status behaviour.

Change-source: pulse-maintainer
2026-10-09 11:18:28 +01:00
pulse-triage[bot] 301bfffeee Withhold webhook receiver text from notification diagnostics
Receivers can echo tokens, alert content or private provider data in a response or body-read error. Ordinary, enhanced and ntfy recovery senders now retain structured HTTP verdicts and bounded byte counts without retaining or formatting that text. Test keeps its existing response shape with an explicit withheld-body summary.

Preserve authoritative failure classes, retry hints, wrapped read causes, occurrence/payload identity, request credentials and the existing 1 MiB read cap. Regression controls reproduce disclosure on the parent and cover the real senders, retry history, interrupted replies, cleanup and bounded summaries. No historical diagnostic rewrite or native provider acceptance is claimed.

Change-source: pulse-maintainer
2026-10-09 11:12:42 +01:00
pulse-triage[bot] b0dc796ffb Explain notification pause, cancellation and in-flight limits
Distinguish global cancellation from quiet-hours holds, queued policy skips from provider receipt, and settings changes from recall or credential revocation. Add connected sender and persistent-queue controls, and run the existing notification guidance suites in docs-only CI.

Contract-Neutral: Documentation, mirrors, tests and documentation-only CI describe existing notification behaviour; no runtime, API, permission, schema, dependency or user-visible feature contract changes.
Change-source: pulse-maintainer
2026-10-08 08:46:03 +01:00
pulse-triage[bot] 53e1bff13c Clarify combined destination severity and tag routing
Correct the empty-filter delivery claim and explain non-exclusive minimum severity, exact all/any tag matching and per-member grouped routing. Bind the existing help and copied examples to the real saved settings and ordinary delivery job builder, without changing routing behaviour.

Contract-Neutral: Documentation and verification only; existing notification routing, alert policy, runtime and API contracts are unchanged.
Change-source: pulse-maintainer
2026-10-07 06:55:39 +01:00
pulse-triage[bot] d82dde586c Integrate reviewed email identity and silent-source History repair
Retain the reviewed Core candidate exactly, including its contributor provenance repair and same-tree proof attribution.

Change-source: pulse-maintainer
2026-10-07 05:29:27 +01:00
pulse-triage[bot] 50173e6a59 Repair email identity and compose silent-source History
Preserve the exact source tree validated at 5989d928108acf80dc38b99cef40935fe17e6e32 while repairing the rejected isolated candidate's integration provenance. Apply rcourtman's original PR2628 proposal daa44ab26c alongside the bounded host-identifiable email repair and current-policy fixture corrections. Original contributor history remains untouched; this new commit records the maintainer's source integration, not a contributor identity change or a new runtime change.

Original-Proposal: daa44ab26c
Change-source: pulse-maintainer
2026-10-07 05:18:52 +01:00
pulse-triage[bot] b0f7a63181 Keep copied webhook close outcomes distinct from recovery
The sender already carries moved_to_agent reasons, but the public PSA template discarded them and described every resolved occurrence as recovered. Preserve each member's reason and successor, explain mixed and unknown outcomes, and exercise copied templates through the real sender plus the shipped Markdown renderer.

Contract-Neutral: Existing webhook help and copied-template regression coverage only; no runtime, endpoint, schema or delivery policy change.
Change-source: pulse-maintainer
2026-10-07 04:02:18 +01:00
pulse-triage[bot] 46447dbac6 Preserve reviewed monitoring repairs with published alert lifecycle fixes
Incorporate the exact current upstream additively while retaining eff676c746 and every accepted commit. PR2576 remains unchanged pending its already-owned connected dashboard fixture repair and aggregate validation; composition alone is not a passing proof or release claim.

Change-source: pulse-maintainer
2026-10-06 19:08:06 +01:00
rcourtman a89c08a59e Drop recovery colours and check marks from moved alert closes
A second review found the moved-alert text was honest but the visuals
still said recovered: Discord kept its green embed, both Teams cards
kept recovery green, Mattermost led with a check emoji, and a grouped
ntfy batch holding a moved alert kept the green check tag. A check mark
on a phone is read before the sentence under it.

Resolved webhook data now carries NotRecovered when any close in the
delivery was not a recovery. The built-in templates switch to neutral
colours and an arrow when it is set, and ntfy uses the arrow tag for a
single alert or a batch. Titles still say Resolved, which stays true
for the closed alert, and ordinary recoveries keep their green.

The render tests now use an isolated data directory, stop their
managers, and hand the captured request over a channel, so they no
longer touch a shared queue or race on the captured body.
2026-10-06 16:17:57 +01:00
rcourtman 123821b02a Carry a typed reason when an alert closes without recovering
When a Pulse agent is linked to a Proxmox node, the node releases its
CPU, memory and disk alerts to the agent, and any node alert still open
closes. The close has to reach integrations so a PagerDuty or webhook
incident opened from the node alert does not stay open forever, but it
went out as a recovery: "pve1 on pve1 is now healthy" for a node still
at 95% memory, with synthesized "recovery projection" evidence behind
it. #1682 is the same complaint from another trigger: a close announced
as "now healthy" when nothing recovered.

A resolved alert can now carry an AlertResolution saying why it closed.
The first reason is moved_to_agent, with the agent's alert resource ID
and name. releaseCanonicalMetricAlert, the disabled-threshold release
pulled out of evaluateCanonicalMetricAlert, takes the resolution, and
clearAlertWithResolution stamps a copy on the alert before it resolves.
It rides the Alert JSON into the resolved callback, the delivery queue,
the history row and the event log. The synthesized closing evidence and
the resolve transition say what happened instead of claiming a recovery
projection.

Notifications still send the close and change only the words: "Memory
alert moved to pve1 (Host Agent). This is not a recovery: check the
agent for the current reading." for webhook messages, a MOVED title
without the green check on ntfy, and "Pulse alert moved" on email and
Apprise. A nil resolution, which every caller passes today, leaves
ordinary recoveries and the disabled-threshold path unchanged. The node
release adopts the reason once the host-agent node link records which
metrics the agent evaluates.
2026-10-06 15:08:43 +01:00
pulse-triage[bot] b992e97ce2 Integrate launch-time upstream with combined table browser proof
Preserve exact 1896f1f2ba history. Resolve the webhook overlap by retaining the reviewed strict update restoration for unknown or ambiguous masks and upstream masked responses plus create/test restoration. Preserve both test groups; align response assertions with masked output and test clearing separately from the retained unknown-mask rejection cases.

Contract-Neutral: Conflict resolution preserves per-key webhook edits, persistence-before-publication, strict uncertain-mask rejection and response confidentiality; no route or feature is added.
Change-source: pulse-maintainer
2026-10-06 09:51:34 +01:00
rcourtman f279dc0b07 Resolve masked webhook values per key and keep responses masked
The webhook editor sends back the ***REDACTED*** values the list returns
for every header, custom field and signing secret the user did not
retype. Three paths mishandled them:

- Update restored the whole saved header or custom-field map whenever any
  value was masked, silently dropping a header or field added in the same
  edit.
- Update echoed the restored saved custom fields, so a Pushover token and
  user key came back in the response even though the list masks them, in
  breach of the api-contracts webhook response clause. Create echoed the
  request, and could store a masked value verbatim.
- The editor's Test button posts the form, so testing an edit after a
  reload sent the literal mask as the token or header.

Resolve each masked value to the saved value of the same key on update and
on a form test that carries a saved webhook's id, keep values typed in the
same request, and drop masks with no saved value. Build list, create and
update responses from one masked shape. Normalization now drops blank
headers, so clearing a header removes it instead of sending an empty
Content-Type that generic receivers cannot parse.
2026-10-06 09:21:41 +01:00
pulse-triage[bot] d4edcd9ce6 Match webhook guide fixtures to existing numeric rounding
The first exact-parent recipe correctly exposed unsafe copied alert strings but also failed a Unicode fixture because the real sender rounds numeric values to one decimal. Retain that failure, expect the existing rounded values explicitly and leave production behaviour and the verified documentation unchanged.

Contract-Neutral: Test expectation repair for existing sender rounding; no runtime, template or delivery contract delta.
Change-source: pulse-maintainer
2026-10-06 05:58:18 +01:00
pulse-triage[bot] 28b0b11837 Make the copied webhook payload escape alert text
The first custom-template example contradicted its own jsonString guidance. Quotes, backslashes, line breaks or JSON member syntax in real alert text could reject the request or alter its payload although a simple test message worked. Escape both string fields, preserve the numeric value and direct structured group consumers to the existing PSA example. Exercise the actual copied template through signed firing and recovery deliveries and the shipped document renderer.

Contract-Neutral: Documentation and tests describe the existing JSON template helper and sender behaviour; no notification runtime or delivery contract changes.
Change-source: pulse-maintainer
2026-10-06 05:44:39 +01:00
pulse-triage[bot] aae30e2baa Explain safe recovery of retained notification failures
A destination edit and a passing Test do not update the settings stored in an old queued delivery. Make the existing recovery help distinguish those paths, explain the passive Telegram header check, and keep the shipped guides in sync. Connect a real rejected HTTP delivery through edit, Test, restart, retained retry and new alert, including current disable, removal and pause controls.

Contract-Neutral: Documents and verifies existing destination-snapshot and retry semantics; no runtime, API, schema or delivery-policy change.
Change-source: pulse-maintainer
2026-10-06 01:30:57 +01:00
rcourtman 06cdaa577a Send built-in webhook template headers on real alerts
A Telegram webhook passed Test while every real alert was rejected with
"message text is empty" (#2540). The Test path always overlaid the
service template's headers, but real deliveries sent the stored header
copy that the UI seeded at creation. An edit can leave that copy blank,
masked or replaced. Telegram reads arguments from a body only when it is
labelled as JSON or form data, and checks text before chat_id, so a JSON
body without a JSON Content-Type produces exactly that error.

When a built-in service renders its own body (no custom template), the
template's static headers describe that body. Apply them on every real
firing and recovery through prepareWebhookDeliveryContext, replace stored
values under any spelling of the name, and route the Test path through
the same helper so Test predicts real delivery. Custom templates and
generic webhooks keep their stored headers.
2026-10-05 22:46:47 +01:00
pulse-triage[bot] d500b4f211 Reconcile delivery failures after releasing alert gates
Commit the normal retry/dead-letter attempt audit before invoking monitoring health reconciliation outside the firing-alert delivery gate. Keep explicit operator actions immediate, transient retry budgets, configuration refusal, policy cancellation and operational links unchanged.

Change-source: pulse-maintainer
2026-10-05 06:40:53 +01:00
pulse-triage[bot] 94a14c78c7 Keep webhook bridge guidance from discarding later alerts
The legacy correlation header omits occurrence start, severity and group members. Show receivers the existing full-precision member data, preserve later incidents and severity updates, and test the copyable templates through the actual signed sender. Keep the freshness verifier and runtime wire format unchanged.

Contract-Neutral: Help, executable examples, tests and sender comments only; notification behaviour, schemas and webhook headers are unchanged.
Change-source: pulse-maintainer
2026-10-04 08:16:23 +01:00
pulse-triage[bot] 3a98883de1 Preserve notification verdicts through SMTP cleanup and ntfy diagnostics
Stop resending mail after the final DATA acceptance solely because QUIT failed. Keep interrupted ntfy recovery rejections authoritative in the retry decision and audit. Preserve missing acceptance, TLS checks, retry budgets and explicit operator recovery; verify all SMTP transports and persistent queue/audit readback with synthetic local receivers.

Change-source: pulse-maintainer
2026-10-03 12:09:42 +01:00
pulse-triage[bot] ac995ef565 Keep pending notification groups occurrence-qualified
Coalesce repeated firing callbacks before delivery into the newest complete occurrence snapshot, retaining distinct and unknown identities and the original grouping deadline. Discard the transient index on cancellation, flush, disable and stop; cancel abandoned firing timers before queue shutdown. Verify ordering, concurrency, routing, persistent restart and actual loopback firing/recovery delivery without changing escalation or retry policy.

Change-source: pulse-maintainer
2026-10-03 03:10:14 +01:00
pulse-triage[bot] 661d7c7b2e Activate paired firing work in the receipt-ordering fixture
The queue discovers one concurrent batch at a time; the first HTTP control incorrectly expected another batch to start while the held response was unfinished. Admit both snapshots through the deferred bootstrap owner and then use normal queue activation. Preserve the runtime policy and timeout, and verify each received message explicitly.

Change-source: pulse-maintainer
2026-10-03 02:35:18 +01:00
pulse-triage[bot] 0dcd592ef2 Keep notification cooldowns ordered by alert occurrence
A late provider completion must retain its own firing receipt without replacing a newer occurrence’s repeat-delivery cooldown. Preserve the latest completion and highest delivered severity within one occurrence, keeping genuine new occurrences and severity increases eligible. Exercise reverse HTTP completion, duplicate admission and durable recovery receipts alongside legacy ordering controls.

Change-source: pulse-maintainer
2026-10-03 02:28:48 +01:00
pulse-triage[bot] 2c57a54ec4 Preserve sending-row crash recovery in the occurrence fixture
Assert surviving row status before restart, then expect the existing sending-to-pending crash recovery after reopening the queue. The initial source-dtamnmrn fixture failure is retained; runtime source and delivery policy are unchanged.

Change-source: pulse-maintainer
2026-10-03 01:20:39 +01:00
pulse-triage[bot] 8f42497b8f Keep delayed alert recovery scoped to its resolved occurrence
Capture the resolved alert before asynchronous callbacks and carry its start/end identity through monitor recovery. Cancel only that occurrence in grouping, cooldown and persistent firing rows, retaining newer incidents, operational links, destination receipts and failed attempts. Keep the explicit identifier-wide cancellation API and legacy callback IDs. Add snapshot, restart and connected queue-to-HTTP regression controls.

Change-source: pulse-maintainer
2026-10-03 01:16:42 +01:00
pulse-triage[bot] 6ab5383412 Let the Apprise confidentiality fixture use one queue dispatcher
SetProcessor already wakes the autonomous queue worker. Observe its committed attempt audit without launching a competing manual batch, keeping all lifecycle, retry-budget, config, failure-class and confidentiality assertions. Report changed lifecycle fields without printing credentials.

Change-source: pulse-maintainer
2026-10-02 21:19:29 +01:00
pulse-triage[bot] 2e331d594d Correct Apprise confidentiality queue and API fixtures
Handle nullable retry-row diagnostics while checking the actual attempt audit and DLQ error; verify omitted stored API keys through the established redacted response type and preserve authorised endpoint/target round-trips. Retain the original diagnostic repair and its adverse proof.

Change-source: pulse-maintainer
2026-10-02 10:17:49 +01:00
pulse-triage[bot] 1ce98f2693 Keep Apprise credentials and private payloads out of diagnostics
Suppress raw CLI targets/output, HTTP response bodies and credential-bearing endpoint paths across firing, recovery, tests, queue audits and settings logs. Preserve exact delivery inputs, typed causes and retry classification; retain structured status, counts and safe validation reasons.

Contract-Neutral: Shared agent-lifecycle and storage-recovery references are unchanged; this diagnostic repair alters no agent or storage behaviour, API schema, destination admission or delivery policy.
Change-source: pulse-maintainer
2026-10-02 03:34:36 +01:00
pulse-triage[bot] 5213b794b2 Revalidate queued alert delivery against current quiet hours
Keep continuous and late replay held without spending a provider attempt. Split mixed batches atomically so eligible alerts retain admitted destinations, occurrence links and retry budgets, and bind saved monitor policy before activating persisted work. Add local receipt, cancellation, rollback, reconstruction and race regression coverage with the owning contracts and verification routes.

Change-source: pulse-maintainer
2026-10-01 23:05:07 +01:00
pulse-triage[bot] 25e526b7e5 fix(notifications): gate queued work until destinations load
The monitor restored notification destinations after constructing a queue whose five-second ticker could consume due jobs. Defer processor installation through destination restore, then wake the backlog before external alert callbacks admit first agent reports. Cover both forced pre-configuration processing and the actual monitor restart path; update the notifications, monitoring and agent-lifecycle contracts.

Change-source: pulse-maintainer
2026-09-27 17:58:07 +01:00
pulse-triage[bot] 75aaf1391c test(notifications): isolate queued routing snapshot
SetProcessor wakes the live queue worker while this test processes a fetched row manually. Defer the row beyond GetPending before installing the processor so a competing worker cannot decide the synchronous assertion.

Change-source: pulse-maintainer
2026-09-27 17:28:04 +01:00
pulse-triage[bot] f235fc37f2 fix(notifications): start queue processing after destination config
A persisted notification that was already due at startup could be terminally cancelled as 'delivery disabled'. NewNotificationManagerWithDataDir woke the queue worker during construction, before the owner had applied saved webhook/email/Apprise configuration, so the still-empty destination list looked like a removed destination.

Install the queue processor without waking it. The worker ticker and later enqueues start delivery once configuration is present. This removes the order/state-dependent failure in TestResolvedGroupingOrdinaryRestart and drops a persisted grouped recovery in production.

Also wait past the queue poll interval in the grouping contract test, add a regression test for the startup ordering, and update the notifications subsystem contract's processor-attachment semantics.

Change-source: pulse-maintainer
2026-09-23 00:01:56 +01:00
pulse-triage[bot] ee8de91eac fix(notifications): deliver severity increases through cooldown
Treat higher delivered severity as new information for the same occurrence without bypassing manager admission, grouping or destination routing. Keep the highest delivered level across late lower-severity completions. Include the contract and observation-to-HTTP/history regressions in this commit.

Change-source: pulse-maintainer
2026-09-22 20:37:00 +01:00
pulse-triage[bot] 9fbc4e7b3a fix(notifications): persist and group resolved alert deliveries
Prevent simultaneous recoveries from bypassing the configured grouping window. Preserve destination receipts and pending restart recovery, and keep PagerDuty incident keys separate. Include the notification contract and regression coverage with the runtime change.

Change-source: pulse-maintainer
2026-09-22 16:52:29 +01:00
pulse-triage[bot] ab225c0d3b fix(alerts): reject stale escalation callback admissions
Revalidate policy, active occurrence, acknowledgement and snooze at the monitoring callback boundary. Preserve current routing and cooldown behaviour with live-incident fixtures. Pin pre-deadline policy changes and queued email routing versus resolution independently.

Change-source: pulse-maintainer
2026-09-10 08:42:59 +01:00
pulse-triage[bot] 0e61fa62c4 fix(notifications): redact mixed-case webhook credential keys
Diagnostic query masking recognised only lowercase credential names, leaving mixed-case and encoded variants visible in URL and transport-error diagnostics. Match decoded names without case while preserving query spelling, unrelated parameters and the original request URL. Add seven regression cases covering diagnostics and wrapped error identity.

Change-source: pulse-maintainer
2026-09-09 05:34:22 +01:00
pulse-triage[bot] c5a99f7d2d test(notifications): cover interrupted transient HTTP rejections
Exercise the intersection of the interrupted-response and 421/423/425 retry repairs, including queue classification and transport recovery history. Synthetic HTTP fixtures only; no queue scheduling or installed receipt claim.

Change-source: pulse-maintainer
2026-09-08 13:11:50 +01:00
pulse-triage[bot] c65ba29bf7 fix(notifications): retain queue retries for transient HTTP rejections
Webhook transport already retries HTTP 421, 423 and 425, but shared classification marked them terminal and discarded the remaining queue retry budget. Align these exceptions with retryable connectivity or receiver failure classes. A synthetic 400-599 transport matrix reproduces the three mismatches and verifies permanent rejections remain terminal without starting storage workers.

Change-source: pulse-maintainer
2026-09-08 12:47:30 +01:00
pulse-triage[bot] 550b2d80a1 fix(notifications): retain HTTP verdict on interrupted response bodies
A truncated diagnostic body currently erases a received HTTP rejection, causing terminal failures such as 403 to consume extra delivery attempts and report a connectivity class. Preserve the HTTP verdict and wrapped read error so existing retry rules still apply. Transport-only regressions reproduce the extra attempt, verify transient recovery and retain successful-response read-error behaviour.

Change-source: pulse-maintainer
2026-09-08 12:14:32 +01:00
pulse-triage[bot] 7a92b60cd9 fix(notifications): honour service-unavailable retry hints
HTTP 503 can advertise a recovery delay through Retry-After, but the transport previously ignored it and retried after the default second. Use the existing bounded parser for 503 as well as 429 without changing retry budgets or terminal-error classification. Add request-spacing coverage for valid and malformed 503 hints and both zero-hint status sequences. The valid 503 test fails before the repair (1.0005s versus 2s); focused race tests pass three times. This longstanding interoperability repair is main-only, not a release-candidate regression backport.

Change-source: pulse-maintainer
2026-09-08 10:04:36 +01:00
pulse-triage[bot] 2a62340706 test(notifications): cover terminal rejection after rate limit
Rate-limit and initial terminal-response tests do not cover their interaction. Verify a later credential rejection stops the transport despite remaining budget and retains accurate final history and event identity, using a queue-free synthetic receiver.

Change-source: pulse-maintainer
2026-09-08 09:46:52 +01:00
pulse-triage[bot] 7243595085 test(notifications): protect destination and occurrence receipt identity
Recovery eligibility depends on both the original destination and the firing occurrence. Existing restart coverage exercises webhooks, but did not directly protect email and Apprise key normalisation from configuration ordering changes or accidental mutation. Add pure-function regression checks for equivalent and changed destinations, incomplete identities and nanosecond-separated recurrences without requiring network delivery or database fixtures.

Change-source: pulse-maintainer
2026-09-08 08:37:35 +01:00
pulse-triage[bot] 8dc59546cb test(notifications): retain recovery evidence across provider rejection
The recovery outage fixture covered only service unavailability. Authentication rejection and rate limiting must also preserve the firing receipt needed for a later recovery, without losing the original failure classification after restart or successful operator retry. Extend the existing loopback fixture to cover these boundaries; this is not installed-provider or release-candidate proof.

Change-source: pulse-maintainer
2026-09-08 07:02:58 +01:00
pulse-triage[bot] f723255347 test(notifications): bound repeated rate-limit retries and history
Incoming webhook destinations can repeatedly return 429. Cover exhaustion for explicit and default retry budgets so response hints cannot reset the attempt ceiling or misreport failed delivery history. Verify each attempt preserves payload and event identity. Correct the transport comment's off-by-one ceiling and remove its delivery guarantee; runtime behaviour is unchanged.

Change-source: pulse-maintainer
2026-09-08 06:11:23 +01:00
pulse-triage[bot] cf7ea5f13e test(notifications): verify ntfy recovery wire contract
Exercise UTF-8 titles and bodies across ordinary firing and recovery, with and without manager restart. Check each firing severity's priority and ensure recovery returns to default priority, as these headers affect phone interruption behaviour.

Change-source: pulse-maintainer
2026-09-08 05:32:24 +01:00
pulse-triage[bot] 82676209bc test(notifications): cover ordinary recovery across restart
Existing outage coverage inserts queue jobs directly and resolved-send coverage seeds a delivery receipt. Exercise normal send and cancellation entry points with loopback HTTP so recovery eligibility depends on actual firing delivery, including after manager restart. This is source acceptance, not installed release qualification.

Change-source: pulse-maintainer
2026-09-08 05:12:26 +01:00
pulse-triage[bot] 69b88efe28 fix(notifications): reject encoded dead-man event endpoints
Validate the decoded URL path so encoded fail/start/log suffixes cannot pass the existing success-endpoint guard. Cover encoded separators, valid base URLs, and runtime rejection without transport or token disclosure.

Change-source: pulse-maintainer
2026-09-08 03:59:00 +01:00
pulse-triage[bot] 4573fe6fca fix(notifications): preserve backoff after Retry-After override
A zero Retry-After on a rate-limited response reset the exponential schedule to zero, causing subsequent transient failures to consume retries immediately. Apply the response delay only to its own wait and retain the normal schedule for later failures. Local HTTP regressions cover both a subsequent 503 and a headerless 429; focused retry tests pass with the race detector over three repetitions.

Change-source: pulse-maintainer
2026-09-08 02:59:11 +01:00