mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-26 13:39:47 +00:00
Make weekly Patrol summary help usable and evidence-aware
Replace the old build and commercial narrative with setup, recipient safety, schedule checks and honest retained-data limits in the existing Intelligence guide. Keep the old repository guide as a pointer and verify the shipped Markdown with meaningful actual-parent controls. Contract-Neutral: Existing-surface help and rendered-documentation verification only; no runtime, route, permission or interface change. Change-source: pulse-maintainer
This commit is contained in:
+116
@@ -494,6 +494,122 @@ When control level is **Controlled**, write actions pause for approval:
|
||||
|
||||
---
|
||||
|
||||
## Weekly summary and email
|
||||
|
||||
Pulse's **This week** summary adds up retained Patrol activity over the last
|
||||
seven days. Open **Patrol → Activity** to read it; use **Settings → Reporting**
|
||||
to schedule the same summary by email. The card, weekly email and **Report type**
|
||||
selector are included in **v6.5.0**. An older build can lack these controls.
|
||||
|
||||
This is a summary of recorded activity, not a complete audit or proof that every
|
||||
resource is healthy. Use individual findings, run history and **Actions** for
|
||||
the result of a particular investigation or fix.
|
||||
|
||||
### Read the summary
|
||||
|
||||
The card normally says **Last 7 days**: a rolling window, not a calendar week.
|
||||
If it says **Since … (older runs are no longer kept)**, its run history covers
|
||||
only part of that window. Refreshing the card reads existing records; it does
|
||||
not run Patrol or recover missing history.
|
||||
|
||||
| Line | What it means and what to check |
|
||||
| --- | --- |
|
||||
| **Patrol runs** | Retained runs, checks and failures in the window. The resource count is the largest number checked in one run, not a count of distinct resources across the week. Read run history for failed or missing checks. |
|
||||
| **New issues** | New-finding totals recorded by those runs. The open severity counts concern findings detected within the window; older open findings are not included. Check the full findings list before concluding that nothing needs attention. |
|
||||
| **Issues resolved** | Recorded automatic resolutions plus manual resolutions still retained. Dismissed and muted findings are described separately. A cleared finding does not establish that an action ran or was independently verified. |
|
||||
| **Investigated** | Recorded investigation outcomes on retained findings. “Fix run, result unknown” is not a verified fix; open the finding for its result and remaining work. |
|
||||
| **Fixes run** | Actions recorded as successfully executed. “Verified afterwards” is a separate count; review failed actions and waiting approvals in **Actions**. Do not run an action again merely to increase the count. |
|
||||
| **Estimated spend** | Recorded Patrol model calls and their estimated USD cost, not an invoice or all Assistant usage. If some calls have no known price, the displayed amount is incomplete, not a zero-cost result. Check [Cost Tracking](AI.md#cost-tracking). |
|
||||
|
||||
The displayed mode is Patrol's **current** mode, not a history of mode changes.
|
||||
Watch-only mode can explain why investigations or fixes were not performed,
|
||||
but changing mode is not a repair for an empty summary.
|
||||
|
||||
### Schedule the weekly email
|
||||
|
||||
Scheduling requires the **advanced reporting** entitlement and an account
|
||||
allowed to manage report schedules. Reading the Patrol card does not itself
|
||||
grant scheduling access. See [Plans and entitlements](PULSE_PRO.md).
|
||||
|
||||
1. Check that email notifications are **enabled and configured** under
|
||||
**Alerts → Notifications**. Listing recipients on a schedule does not
|
||||
configure a mail provider or enable email.
|
||||
2. Open **Settings → Reporting**, choose **Create schedule**, then set
|
||||
**Report type** to **Patrol weekly summary**.
|
||||
3. Enter a schedule name, weekday, time and an IANA **Timezone**, such as
|
||||
`Europe/London`. The summary is weekly, covers the last seven days, and is
|
||||
sent as HTML and plain text email. It is not a PDF/CSV attachment, a
|
||||
resource/tag-filtered report, or a saved disk copy.
|
||||
4. Set **Email recipients** deliberately. Blank uses the existing email
|
||||
notification recipients; if none are configured, delivery can fall back
|
||||
to the sender address. Use explicit authorised recipients to avoid that
|
||||
ambiguity. The email can contain resource names, findings and costs.
|
||||
5. Save with **Enabled** selected for automatic runs. **Run now** sends a real
|
||||
email; it is not a preview or a test of future scheduled delivery. Use it
|
||||
only when those recipients should receive the summary.
|
||||
|
||||
The Report type choice appears when the session reports AI as enabled. An
|
||||
existing summary keeps its type when edited after AI is switched off. If the
|
||||
choice is missing, check the installed version, current workspace, AI settings
|
||||
and reporting access; do not change Patrol's autonomy mode, re-enrol agents or
|
||||
create an API token just to reveal it.
|
||||
|
||||
### Check a missing email or empty summary
|
||||
|
||||
- **No recorded runs:** check Patrol's enabled state, configured provider,
|
||||
ordinary run history and errors. “Patrol has not run” can also reflect an
|
||||
unavailable Patrol service, not proof that the environment had no problems.
|
||||
Do not force a run, restart Pulse or change retention just to fill the card.
|
||||
- **Failed schedule:** read **Last run** and the saved error in Reporting. On
|
||||
a narrow screen, use the same signed-in page at a wider viewport to see
|
||||
that column. A missing Patrol service and missing email configuration are
|
||||
different failures. Preserve the original error; do not repeatedly use
|
||||
Run now or send synthetic alerts to diagnose them.
|
||||
- **Run marked OK but no email received:** that status means Pulse's sender
|
||||
returned success, not that the message reached the recipient's inbox.
|
||||
Check the selected recipients and the mail provider's delivery or rejection
|
||||
record, then the mailbox's filtering. A successful alert Test does not prove
|
||||
that this schedule ran or used the intended recipients.
|
||||
- **Email links missing:** links depend on the configured Pulse public URL.
|
||||
Open Patrol in your existing authenticated browser; do not make Pulse
|
||||
publicly accessible or disable TLS to make an email link work.
|
||||
|
||||
Keep full mail errors, recipient addresses, credentials and exports private.
|
||||
Share only a locally reviewed, redacted error and the relevant schedule time
|
||||
and outcome; see [Getting Help](TROUBLESHOOTING.md#-getting-help).
|
||||
|
||||
### Honest limits of the data
|
||||
|
||||
- Run history retains at most **100 runs**. Event-triggered activity can
|
||||
exhaust it before seven days. The partial-window notice concerns run
|
||||
retention only; its absence does not certify all other lines as complete.
|
||||
- Resolved findings can be purged after **24 hours**, and dismissed findings
|
||||
after **30 days**. Manual resolutions, dismissals and investigation outcomes
|
||||
on purged findings can disappear from these totals. Automatic resolution
|
||||
totals come from retained runs, so the lines need not reconcile exactly.
|
||||
- Actions have their own retained audit records, but the digest reads a bounded
|
||||
set and can show an empty action line when that source is unavailable.
|
||||
Check **Actions** itself; zero in this summary is not proof that no action
|
||||
took place. Pending approvals can include actions created before the window.
|
||||
- Model spend depends on recorded usage and known prices. This summary cannot
|
||||
establish that caching, a budget limit or a provider's bill is correct.
|
||||
|
||||
### API
|
||||
|
||||
For an existing authenticated integration, `GET /api/ai/patrol/digest` requires
|
||||
`ai:execute` scope. Optional `days` is an integer from **1 to 30**, default
|
||||
**7**; invalid values return 400. Scheduled email always uses seven days.
|
||||
The response groups `window`, `mode`, `runs`, `findings`, `investigations`,
|
||||
`actions`, `alerts` and `spend`. `window.history_complete` and
|
||||
`window.history_since` describe the run-retention limitation above, not a
|
||||
whole-report completeness guarantee.
|
||||
|
||||
A zero response can be returned when the Patrol service is unavailable.
|
||||
Authentication, scope or transport errors are not a zero result. Prefer the
|
||||
signed-in card for a one-off check; never extract a session cookie or put an
|
||||
API token in a command, URL or public report. See [API authentication](API.md#-authentication)
|
||||
for the private header-file approach when an integration needs it.
|
||||
|
||||
## Configuration
|
||||
|
||||
Configure providers in the UI: **Settings → Pulse Intelligence → Provider & Models**
|
||||
|
||||
@@ -1,105 +1,6 @@
|
||||
# Patrol Weekly Digest
|
||||
|
||||
Status: building — endpoint and in-app "This week" card on `main` (PRs #1856
|
||||
and #1860, 2026-09-02); the weekly email is the `patrol_digest` report
|
||||
schedule kind, and Settings > Reporting creates it through the "Report type"
|
||||
choice on the schedule form (2026-10-02). Demand ledger:
|
||||
`pulse-pro/FEATURE_REQUESTS.md`, "Patrol weekly digest (what Patrol did for
|
||||
you)", a named bet under the Patrol operations loop.
|
||||
|
||||
## The job, in the customer's words
|
||||
|
||||
"Show me what I am paying for." A Pro customer turns Patrol on, it runs about
|
||||
five times a day, and nothing in Pulse ever adds that up. They see individual
|
||||
findings when they open the page and individual emails when a finding fires,
|
||||
but never the week: how often Patrol looked, what it caught, what it fixed,
|
||||
what it cost. The 2026-09-01 assessment found 33 of 175 Pro subscriptions past
|
||||
due and 80 percent of paying installs never seeing the paid loop fire. A
|
||||
customer who cannot see the work stops paying for it.
|
||||
|
||||
The least-expert plausible reader is a homelab operator who set Patrol up once
|
||||
and opens Pulse when an alert email arrives. They do not know what an
|
||||
"investigation", a "verdict", or an "evidence class" is. The digest must read
|
||||
as a plain weekly account, and every number must lead to something they can
|
||||
click or a decision they can make.
|
||||
|
||||
## What the digest reports
|
||||
|
||||
Everything below is computed from data Pulse already records. No new
|
||||
telemetry fields; the readout task grades this bet from support and issue
|
||||
mentions.
|
||||
|
||||
| Line | Source | What the reader does with it |
|
||||
| --- | --- | --- |
|
||||
| Runs: how many times Patrol checked, how many checks in total, how many resources it covered, when it last ran | `PatrolRunRecord` history (`internal/ai/patrol.go`, capped at 100 runs) | Confirms Patrol is alive. If runs are zero or failed, the card says so and points at Patrol setup. |
|
||||
| Mode: monitor, approval, assisted, or full | `Service.GetEffectivePatrolAutonomyLevel` | Explains why actions were or were not taken. Monitor mode with fixable findings is the upgrade prompt, stated plainly. |
|
||||
| New issues this week, and how many are still open by severity | run `new_findings` totals plus the findings store for still-tracked findings detected in the window | Open critical or warning issues are the thing to look at; the count links to the findings list. |
|
||||
| Issues resolved and how many Patrol resolved on its own | run `resolved_findings` totals plus manual resolutions still in the findings store | This is the "it did something" line. |
|
||||
| Issues you dismissed or muted | finding lifecycle events (`dismissed`, `suppressed`) in the window | Reminds the reader what they told Patrol to ignore. |
|
||||
| Investigations and their outcomes | finding lifecycle `investigation_outcome` events in the window | Shows the paid loop firing; outcomes that need attention are named. |
|
||||
| Actions proposed, approved, executed, verified, failed, and still waiting | canonical action audit records with `origin.surface = patrol` (`internal/unifiedresources`) | "Waiting" links straight to Actions and approvals. |
|
||||
| Alerts Patrol looked into | alert-triggered runs (`alert_fired`, `alert_flapping`) and their distinct alert identifiers | Shows Patrol responding to the reader's own alerts, not just its schedule. |
|
||||
| Estimated model spend, tokens, and calls | `internal/ai/cost` usage events with `use_case = patrol` | Answers "what does this cost me" without opening the AI cost dashboard. Marked as an estimate; unknown pricing is stated, never zeroed. |
|
||||
|
||||
Deliberately left out: per-run tool call traces, evidence classes, verdict
|
||||
strings, model names, and anything the reader cannot act on. Those stay in run
|
||||
history and the Actions audit, one click away.
|
||||
|
||||
## Honest limits of the data
|
||||
|
||||
- Run history keeps the last 100 runs. At five or six runs a day a week fits,
|
||||
but a busy install with event-triggered runs can overflow. The payload
|
||||
carries `window.history_complete` and `window.history_since`; the card says
|
||||
"since <date>" instead of "this week" when the window is cut short.
|
||||
- Resolved findings are purged from the findings store 24 hours after
|
||||
resolution, and dismissed findings after 30 days. Resolution totals therefore
|
||||
come from run records, and severity is only reported for findings still
|
||||
tracked. Investigation outcomes are read from lifecycle events on tracked
|
||||
findings, so a finding that was investigated, fixed, and purged more than a
|
||||
day ago no longer contributes. Executed and verified actions do not have this
|
||||
gap: action audit records are durable.
|
||||
- Spend is `cost.EstimateUSD` over recorded usage events. When the model has
|
||||
no known price the digest says pricing is unknown rather than reporting a
|
||||
smaller number.
|
||||
|
||||
## Surface
|
||||
|
||||
**In-app card first.** A "This week" card at the top of the Patrol page's
|
||||
Activity tab, above Verified outcomes
|
||||
(`frontend-modern/src/features/patrol/PatrolWeeklyDigestCard.tsx`, backed by
|
||||
`GET /api/ai/patrol/digest?days=7`). It costs nothing to deliver, every paying
|
||||
install can see it, and the Activity tab is already where "what happened"
|
||||
questions are answered. The Inbox stays a decision surface and does not gain a
|
||||
summary card.
|
||||
|
||||
**Weekly email second.** The past-due population is the population that has
|
||||
stopped opening Pulse, so the email is the slice that reaches them. It is a
|
||||
report schedule kind, `patrol_digest`, on the report schedule API
|
||||
(`POST /api/admin/reports/schedules` with `"kind": "patrol_digest"`): the
|
||||
existing scheduler, cadence, recipients, and Pro reporting entitlement are
|
||||
reused, and the run renders the same digest as plain-language HTML and text
|
||||
(`internal/api/patrol_digest_email.go`) through the tenant email config via
|
||||
`SendEmailWithRetry`. Digest schedules are weekly and email-only; nothing is
|
||||
written to disk. A run without an email destination fails with a message that
|
||||
names the missing setting instead of silently doing nothing. Webhook and
|
||||
Apprise channels are out of scope.
|
||||
|
||||
In Settings > Reporting, "Create schedule" offers a "Report type" choice
|
||||
between the performance report and the Patrol weekly summary. The choice only
|
||||
appears while the session reports that Patrol can run (AI on with a provider
|
||||
configured, the same capability that shows the Patrol navigation), and an
|
||||
existing summary schedule keeps showing its type so it can be edited after AI
|
||||
is switched off. Choosing the summary reduces the form to a name, weekday,
|
||||
time, timezone, and optional recipients: cadence is pinned to weekly, delivery
|
||||
to email, and the format, resources, tag filter, retention, attachment, and
|
||||
save-copy controls are hidden because the server fixes those values. The
|
||||
schedules table describes a summary's scope as "Patrol activity, last 7 days".
|
||||
|
||||
## API
|
||||
|
||||
`GET /api/ai/patrol/digest` — requires `ai:execute` scope like the other
|
||||
Patrol read endpoints. Query `days` (1 to 30, default 7). Returns the window,
|
||||
current mode, and the run, finding, investigation, action, alert, and spend
|
||||
rollups described above. Empty history returns zero counts with
|
||||
`window.history_complete = true`; a missing AI or Patrol service returns the
|
||||
same zero shape so the card can render its "Patrol has not run" state.
|
||||
For setup, interpretation, email checks and retained-data limits, see
|
||||
[Weekly summary and email](AI.md#weekly-summary-and-email) in the Pulse
|
||||
Intelligence guide. The summary uses existing Patrol activity; it is not a
|
||||
complete audit or proof that every resource is healthy.
|
||||
|
||||
@@ -494,6 +494,122 @@ When control level is **Controlled**, write actions pause for approval:
|
||||
|
||||
---
|
||||
|
||||
## Weekly summary and email
|
||||
|
||||
Pulse's **This week** summary adds up retained Patrol activity over the last
|
||||
seven days. Open **Patrol → Activity** to read it; use **Settings → Reporting**
|
||||
to schedule the same summary by email. The card, weekly email and **Report type**
|
||||
selector are included in **v6.5.0**. An older build can lack these controls.
|
||||
|
||||
This is a summary of recorded activity, not a complete audit or proof that every
|
||||
resource is healthy. Use individual findings, run history and **Actions** for
|
||||
the result of a particular investigation or fix.
|
||||
|
||||
### Read the summary
|
||||
|
||||
The card normally says **Last 7 days**: a rolling window, not a calendar week.
|
||||
If it says **Since … (older runs are no longer kept)**, its run history covers
|
||||
only part of that window. Refreshing the card reads existing records; it does
|
||||
not run Patrol or recover missing history.
|
||||
|
||||
| Line | What it means and what to check |
|
||||
| --- | --- |
|
||||
| **Patrol runs** | Retained runs, checks and failures in the window. The resource count is the largest number checked in one run, not a count of distinct resources across the week. Read run history for failed or missing checks. |
|
||||
| **New issues** | New-finding totals recorded by those runs. The open severity counts concern findings detected within the window; older open findings are not included. Check the full findings list before concluding that nothing needs attention. |
|
||||
| **Issues resolved** | Recorded automatic resolutions plus manual resolutions still retained. Dismissed and muted findings are described separately. A cleared finding does not establish that an action ran or was independently verified. |
|
||||
| **Investigated** | Recorded investigation outcomes on retained findings. “Fix run, result unknown” is not a verified fix; open the finding for its result and remaining work. |
|
||||
| **Fixes run** | Actions recorded as successfully executed. “Verified afterwards” is a separate count; review failed actions and waiting approvals in **Actions**. Do not run an action again merely to increase the count. |
|
||||
| **Estimated spend** | Recorded Patrol model calls and their estimated USD cost, not an invoice or all Assistant usage. If some calls have no known price, the displayed amount is incomplete, not a zero-cost result. Check [Cost Tracking](AI.md#cost-tracking). |
|
||||
|
||||
The displayed mode is Patrol's **current** mode, not a history of mode changes.
|
||||
Watch-only mode can explain why investigations or fixes were not performed,
|
||||
but changing mode is not a repair for an empty summary.
|
||||
|
||||
### Schedule the weekly email
|
||||
|
||||
Scheduling requires the **advanced reporting** entitlement and an account
|
||||
allowed to manage report schedules. Reading the Patrol card does not itself
|
||||
grant scheduling access. See [Plans and entitlements](PULSE_PRO.md).
|
||||
|
||||
1. Check that email notifications are **enabled and configured** under
|
||||
**Alerts → Notifications**. Listing recipients on a schedule does not
|
||||
configure a mail provider or enable email.
|
||||
2. Open **Settings → Reporting**, choose **Create schedule**, then set
|
||||
**Report type** to **Patrol weekly summary**.
|
||||
3. Enter a schedule name, weekday, time and an IANA **Timezone**, such as
|
||||
`Europe/London`. The summary is weekly, covers the last seven days, and is
|
||||
sent as HTML and plain text email. It is not a PDF/CSV attachment, a
|
||||
resource/tag-filtered report, or a saved disk copy.
|
||||
4. Set **Email recipients** deliberately. Blank uses the existing email
|
||||
notification recipients; if none are configured, delivery can fall back
|
||||
to the sender address. Use explicit authorised recipients to avoid that
|
||||
ambiguity. The email can contain resource names, findings and costs.
|
||||
5. Save with **Enabled** selected for automatic runs. **Run now** sends a real
|
||||
email; it is not a preview or a test of future scheduled delivery. Use it
|
||||
only when those recipients should receive the summary.
|
||||
|
||||
The Report type choice appears when the session reports AI as enabled. An
|
||||
existing summary keeps its type when edited after AI is switched off. If the
|
||||
choice is missing, check the installed version, current workspace, AI settings
|
||||
and reporting access; do not change Patrol's autonomy mode, re-enrol agents or
|
||||
create an API token just to reveal it.
|
||||
|
||||
### Check a missing email or empty summary
|
||||
|
||||
- **No recorded runs:** check Patrol's enabled state, configured provider,
|
||||
ordinary run history and errors. “Patrol has not run” can also reflect an
|
||||
unavailable Patrol service, not proof that the environment had no problems.
|
||||
Do not force a run, restart Pulse or change retention just to fill the card.
|
||||
- **Failed schedule:** read **Last run** and the saved error in Reporting. On
|
||||
a narrow screen, use the same signed-in page at a wider viewport to see
|
||||
that column. A missing Patrol service and missing email configuration are
|
||||
different failures. Preserve the original error; do not repeatedly use
|
||||
Run now or send synthetic alerts to diagnose them.
|
||||
- **Run marked OK but no email received:** that status means Pulse's sender
|
||||
returned success, not that the message reached the recipient's inbox.
|
||||
Check the selected recipients and the mail provider's delivery or rejection
|
||||
record, then the mailbox's filtering. A successful alert Test does not prove
|
||||
that this schedule ran or used the intended recipients.
|
||||
- **Email links missing:** links depend on the configured Pulse public URL.
|
||||
Open Patrol in your existing authenticated browser; do not make Pulse
|
||||
publicly accessible or disable TLS to make an email link work.
|
||||
|
||||
Keep full mail errors, recipient addresses, credentials and exports private.
|
||||
Share only a locally reviewed, redacted error and the relevant schedule time
|
||||
and outcome; see [Getting Help](TROUBLESHOOTING.md#-getting-help).
|
||||
|
||||
### Honest limits of the data
|
||||
|
||||
- Run history retains at most **100 runs**. Event-triggered activity can
|
||||
exhaust it before seven days. The partial-window notice concerns run
|
||||
retention only; its absence does not certify all other lines as complete.
|
||||
- Resolved findings can be purged after **24 hours**, and dismissed findings
|
||||
after **30 days**. Manual resolutions, dismissals and investigation outcomes
|
||||
on purged findings can disappear from these totals. Automatic resolution
|
||||
totals come from retained runs, so the lines need not reconcile exactly.
|
||||
- Actions have their own retained audit records, but the digest reads a bounded
|
||||
set and can show an empty action line when that source is unavailable.
|
||||
Check **Actions** itself; zero in this summary is not proof that no action
|
||||
took place. Pending approvals can include actions created before the window.
|
||||
- Model spend depends on recorded usage and known prices. This summary cannot
|
||||
establish that caching, a budget limit or a provider's bill is correct.
|
||||
|
||||
### API
|
||||
|
||||
For an existing authenticated integration, `GET /api/ai/patrol/digest` requires
|
||||
`ai:execute` scope. Optional `days` is an integer from **1 to 30**, default
|
||||
**7**; invalid values return 400. Scheduled email always uses seven days.
|
||||
The response groups `window`, `mode`, `runs`, `findings`, `investigations`,
|
||||
`actions`, `alerts` and `spend`. `window.history_complete` and
|
||||
`window.history_since` describe the run-retention limitation above, not a
|
||||
whole-report completeness guarantee.
|
||||
|
||||
A zero response can be returned when the Patrol service is unavailable.
|
||||
Authentication, scope or transport errors are not a zero result. Prefer the
|
||||
signed-in card for a one-off check; never extract a session cookie or put an
|
||||
API token in a command, URL or public report. See [API authentication](API.md#-authentication)
|
||||
for the private header-file approach when an integration needs it.
|
||||
|
||||
## Configuration
|
||||
|
||||
Configure providers in the UI: **Settings → Pulse Intelligence → Provider & Models**
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
import { readFileSync } from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { renderDocMarkdown } from '@/features/docs/docMarkdown';
|
||||
|
||||
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../..');
|
||||
const read = (relative: string) => readFileSync(path.join(root, relative), 'utf8');
|
||||
const markdown = read('docs/AI.md');
|
||||
const article = document.createElement('article');
|
||||
const rendered = document.createElement('article');
|
||||
rendered.innerHTML = renderDocMarkdown(markdown, 'AI');
|
||||
for (
|
||||
let element = rendered.querySelector('#weekly-summary-and-email');
|
||||
element;
|
||||
element = element.nextElementSibling
|
||||
) {
|
||||
if (element.tagName === 'H2' && element.id !== 'weekly-summary-and-email') break;
|
||||
article.append(element.cloneNode(true));
|
||||
}
|
||||
const text = article.textContent!.replace(/\s+/g, ' ');
|
||||
|
||||
// Exercise the actual shipped Markdown, not a second copy of the advice.
|
||||
describe('Patrol weekly summary help', () => {
|
||||
it('ships operator help instead of a private build or sales plan', () => {
|
||||
expect(read('frontend-modern/public/docs/AI.md')).toBe(markdown);
|
||||
expect(text).toContain('included in v6.5.0');
|
||||
expect(text).not.toMatch(/Status: building|past due|stops paying|FEATURE_REQUESTS/);
|
||||
expect(read('docs/PATROL_WEEKLY_DIGEST.md')).toContain('(AI.md#weekly-summary-and-email)');
|
||||
expect(article.querySelector('#read-the-summary')).not.toBeNull();
|
||||
expect(article.querySelector('#check-a-missing-email-or-empty-summary')).not.toBeNull();
|
||||
});
|
||||
|
||||
it('makes enabled mail and reporting access prerequisites of the setup flow', () => {
|
||||
const steps = Array.from(article.querySelectorAll('ol li'), (item) =>
|
||||
item.textContent!.replace(/\s+/g, ' '),
|
||||
);
|
||||
expect(steps).toHaveLength(5);
|
||||
expect(text).toContain('advanced reporting entitlement');
|
||||
expect(steps[0]).toContain(
|
||||
'Listing recipients on a schedule does not configure a mail provider or enable email',
|
||||
);
|
||||
expect(steps[1]).toContain('Report type to Patrol weekly summary');
|
||||
expect(steps[2]).toContain('Timezone');
|
||||
expect(steps[2]).toContain('not a PDF/CSV attachment');
|
||||
});
|
||||
|
||||
it('warns about recipient fallback and real Run now delivery', () => {
|
||||
expect(text).toContain('delivery can fall back to the sender address');
|
||||
expect(text).toContain('Run now sends a real email; it is not a preview');
|
||||
expect(text).toContain("Pulse's sender returned success");
|
||||
});
|
||||
|
||||
it('does not turn run or action counters into whole-estate acceptance', () => {
|
||||
expect(text).toContain('largest number checked in one run, not a count of distinct resources');
|
||||
expect(text).toContain('older open findings are not included');
|
||||
expect(text).toContain('current mode, not a history of mode changes');
|
||||
expect(text).toContain('zero in this summary is not proof that no action took place');
|
||||
expect(text).toContain('Pending approvals can include actions created before the window');
|
||||
});
|
||||
|
||||
it('separates missing inputs, partial history, unknown spend and inbox receipt', () => {
|
||||
expect(text).toContain('partial-window notice concerns run retention only');
|
||||
expect(text).toContain('displayed amount is incomplete, not a zero-cost result');
|
||||
expect(text).toContain('not that the message reached the recipient');
|
||||
expect(text).toContain('unavailable Patrol service, not proof');
|
||||
expect(text).toContain(
|
||||
'Manual resolutions, dismissals and investigation outcomes on purged findings',
|
||||
);
|
||||
});
|
||||
|
||||
it('preserves API errors and routes private evidence to real help anchors', () => {
|
||||
expect(text).toContain('ai:execute scope');
|
||||
expect(text).toContain('invalid values return 400');
|
||||
expect(text).toContain('Authentication, scope or transport errors are not a zero result');
|
||||
expect(text).toContain('never extract a session cookie');
|
||||
for (const [slug, fragment] of [
|
||||
['AI', 'cost-tracking'],
|
||||
['API', '-authentication'],
|
||||
['TROUBLESHOOTING', '-getting-help'],
|
||||
]) {
|
||||
const link = article.querySelector(`a[href="/docs/${slug}#${fragment}"]`);
|
||||
expect(link?.hasAttribute('data-doc-link')).toBe(true);
|
||||
const target = document.createElement('article');
|
||||
target.innerHTML = renderDocMarkdown(read(`docs/${slug}.md`), slug);
|
||||
expect(target.querySelector(`[id="${fragment}"]`)).not.toBeNull();
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user