Commit graph

32 commits

Author SHA1 Message Date
rcourtman
97f894b009 Retire Relay labels and upsells inside Pulse
Relay left public checkout on 2026-09-29: it only ever connected the
Pulse Mobile app, which retires on 31 March 2027, and existing Relay
subscribers now carry Pro entitlements. The app still sold it. Every
Community install saw a "Get alerts on your phone ... Available with
Relay and Pro plans" upgrade panel on Alerts destinations, the plan
screen offered a Relay card with "Remote web access via Relay", and the
settings section was called Remote Access although Relay never reached
the web UI.

The Alerts push panel now renders only on instances that have the relay
feature, with no upsell. The settings section, nav, header and locale
catalogs say Pulse Mobile and carry the retirement date. Community sees
only the Pro comparison card and Relay-tier licenses see none; gated
mobile features name Pro as their minimum plan. The relay feature is
labelled "Pulse Relay (Mobile Connection)" in the catalog, plan copy no
longer claims remote web access, the backend pairing diagnostics point
at Settings > Pulse Mobile, and the user docs, including PRIVACY.md,
state that Relay does not provide remote web UI access.
2026-09-29 13:19:54 +01:00
pulse-triage[bot]
1b422dd1a6 Document maintenance API and repair documentation section links
Lands contributor PR #2067 (head 5eeea72a3a, author rcourtman) as a single maintainer commit on main. The PR documents the authenticated /api/resources/{id}/operator-state maintenance window contract and repairs GitHub-compatible documentation heading fragments.

Composed from the reviewed web-product candidate tree 68465bc48d (candidate 20260921T054028Z-web-product), which resolved the conflicts against main and replaced the unavailable github-slugger dependency with a dependency-free GitHub-compatible heading slugger. The tree is unchanged from that reviewed candidate; only the commit shape differs so the fdb2be15be..HEAD provenance range contains no external PR commit.

Validation retained from that candidate: vite build passed, check-bundle-size.mjs passed (vendor within budget), 61 focused vitest tests passed, and the offline Playwright docs-fragment-navigation run passed with a content-addressed browser-verification.json receipt based at fdb2be15be.

Change-source: pulse-maintainer
2026-09-21 07:23:24 +01:00
rcourtman
eecf45fafd Email the Patrol weekly summary as a report schedule kind
The customers most likely to lapse are the ones who stopped opening Pulse,
so the in-app "This week" card cannot reach them. Report schedules gain a
kind: the default resources kind is the existing PDF or CSV performance
report, and patrol_digest emails the same weekly "what Patrol did for you"
rollup the Patrol page shows, in plain language, for the whole workspace.
It reuses the existing scheduler, cadence, recipients, tenant email config,
and Pro advanced-reporting entitlement rather than adding a second
scheduler. Digest schedules are weekly and email-only; the server fixes
scope, format, and attachments, and a run with no AI service, no Patrol, or
no email destination records a last_error that names the missing piece
instead of sending an empty week. Nothing is written to disk.

The digest assembly moves from the HTTP handler into
AISettingsHandler.BuildPatrolDigest so the schedule runner and the
endpoint share one code path. docs/MSP.md documents the kind for
providers; the Settings > Reporting "Report type" selector follows in a
separate change once it has a Pro-licensed browser pass.
2026-09-02 11:15:22 +01:00
rcourtman
8ea94d792b Add the Patrol weekly digest endpoint
Nothing in Pulse showed a paying customer what Patrol had done for them:
about 164 runs a month per install, findings raised, investigations and
fixes, and none of it summarised. GET /api/ai/patrol/digest rolls the last
N days (default 7, max 30) up from records Pulse already keeps: run
history, the findings store, Patrol-origin action audits, and the usage
cost store. It adds no telemetry and persists nothing. The payload
reports when the bounded run history no longer covers the window and when
model pricing is unknown, rather than quietly under-counting.

This is the first slice of the "Patrol weekly digest" named bet in the
pulse-pro demand ledger; the in-app "This week" card follows once its
browser pass is recorded. docs/PATROL_WEEKLY_DIGEST.md holds the design
note and the honest limits of each line.

status.json registers the patrol-value-visibility coverage gap, the
candidate lane, and its work claim. It also drops the second, identical
copy of the ai-provider-guided-setup coverage gap that landed with #1853;
the duplicate id fails the status audit on main for every pull request.
2026-09-02 08:53:50 +01:00
rcourtman
ac328e1eee Guide the Patrol model choice with cost preview and budget pause
Forty-two percent of paying installs never get Patrol running, and the
support and issue evidence says the wall is model choice and cost: a
prospect asked which models Pulse recommends before trying, a Pro customer
picked Flash-Lite to save money and Patrol then could not file verdicts,
and a mispriced Opus row tripped the 20 USD budget so the circuit breaker
disabled Patrol with nothing but a log line (#1789).

Answer both questions at the point of choice. The Patrol and shared
default model pickers pin guided models in a "Suggested for Patrol"
section with recommended / suggested / caution markers and a one-line
reason: the Ollama preflight blessing is the only recommended entry,
Gemini Flash-Lite the only caution, and cloud starting points are labelled
price-driven and unqualified until this install's own readiness pass
upgrades them to "Verified on this install". A server-computed cost
preview sits under the model choice: monthly estimate from Pulse's price
table, the schedule, and the install's own median full run once three
priced runs exist (a measured 104,528-in / 4,491-out run otherwise), with
the assumption stated and a token explained once, plus 30-day spend
against budget. Each schedule preset is priced in the Schedule select.

When a per-token model is picked while the schedule is still the 6-hour
default, the cost model proposes the slowest preset that keeps scheduled
runs under half the budget (20 USD reference when none is set) and says
what the slower check costs in detection delay; a schedule the install
already chose is never changed.

A used-up budget is now a spending decision, not a provider fault: the
budget refusal is a typed sentinel with the figures, classified as the
budget_exhausted cause, excluded from circuit-breaker accounting, and
promoted into the Patrol block state, so the Patrol page shows "Patrol
paused" with the spend and limit and a "Raise the cost budget" action
instead of "Check Patrol model".
2026-09-02 07:55:42 +01:00
Richard Courtman
79967177ea Enforce explicit SSO administrator grants 2026-08-31 00:43:42 +01:00
pulse-triage[bot]
0f2d7ae055 Make notification delivery failures actionable 2026-08-31 00:39:53 +01:00
rcourtman
ff507a6e44 feat(alerts): add per-alert snooze 2026-08-27 17:20:32 +01:00
rcourtman
f4e1e47e74 feat(alerts): add external dead-man monitoring 2026-08-27 16:27:46 +01:00
pulse-triage[bot]
e88583866a Repair alert delivery governance proof
Bind the delivery diagnosis, active-card presentation, and additive event log to their canonical contracts and recognized API/frontend tests. Sync the shipped API reference, record current browser evidence, and restore sorted truthful control-plane status evidence.

Change-source: pulse-maintainer
2026-08-26 21:29:03 +01:00
pulse-triage[bot]
75b6655d6e Restore Proxmox node network details
Refs #1716

Change-source: pulse-maintainer
2026-08-26 15:17:12 +01:00
rcourtman
a0aa5d4e55 Bind OIDC plan docs to RBAC governance
Change-source: pulse-maintainer
2026-08-26 02:36:04 +01:00
rcourtman
bce5564025 fix notification terminal failure recovery 2026-08-23 09:05:54 +01:00
rcourtman
903b579f8a Add durable Patrol objectives 2026-08-13 23:59:33 +01:00
rcourtman
647f3e6a6c Keep shipped upgrade guide in release sync 2026-08-12 17:43:09 +01:00
rcourtman
3adeb77d60
Secure configuration transfer authorization (#1714)
Co-authored-by: Pulse Autonomous Maintainer <rcourtman@users.noreply.github.com>
2026-08-12 07:32:50 +01:00
rcourtman
be18f99d24 fix(rbac): make SSO user access manageable 2026-08-09 13:36:07 +01:00
rcourtman
16179dd0a5 Improve 6.2 usability across core workflows
Some checks are pending
Build and Test / Secret Scan (push) Waiting to run
Build and Test / Script smoke tests & backend build (push) Blocked by required conditions
Build and Test / Detect changed areas (push) Waiting to run
Build and Test / Frontend (push) Blocked by required conditions
Build and Test / Backend tests (api) (push) Blocked by required conditions
Build and Test / Backend tests (rest-0) (push) Blocked by required conditions
Build and Test / Backend tests (rest-1) (push) Blocked by required conditions
Helm CI / Lint and Render Chart (push) Waiting to run
Public docs / check (push) Waiting to run
Core E2E Tests / Playwright Core E2E (shard 1/8) (push) Waiting to run
Core E2E Tests / Playwright Core E2E (shard 2/8) (push) Waiting to run
Build and Test / Benchmarks (push) Blocked by required conditions
Canonical Governance / governance (push) Waiting to run
Core E2E Tests / Playwright Core E2E (shard 5/8) (push) Waiting to run
Core E2E Tests / Playwright Core E2E (shard 6/8) (push) Waiting to run
Core E2E Tests / Playwright Core E2E (shard 7/8) (push) Waiting to run
Core E2E Tests / Playwright Core E2E (shard 8/8) (push) Waiting to run
Core E2E Tests / Agent registration lifecycle (push) Waiting to run
Core E2E Tests / E2E verdict (push) Blocked by required conditions
Unified Agent Native Verification / Linux ARM64 (push) Waiting to run
Unified Agent Native Verification / Linux x64 (push) Waiting to run
Unified Agent Native Verification / Windows x64 (push) Waiting to run
Unified Agent Native Verification / macOS ARM64 (push) Waiting to run
Unified Agent Native Verification / macOS Intel (push) Waiting to run
Unified Agent Native Verification / FreeBSD cross-build contract (push) Waiting to run
Core E2E Tests / Playwright Core E2E (shard 3/8) (push) Waiting to run
Core E2E Tests / Playwright Core E2E (shard 4/8) (push) Waiting to run
2026-08-09 01:16:15 +01:00
rcourtman
c37a62b3ad Ship the architecture and contributing docs the index links to
The documentation index links both, and the viewer resolved them to routes
with no asset behind them, so following either reached the not-shipped
state. Both are public repository documents, so ship them alongside the
rest and let the links work.

They live at the repository root rather than under docs/, so the sync test
maps them the way it already maps SECURITY.md and TERMS.md.

CONTRIBUTING.md links as docs/AI_TRANSPARENCY.md, which is the path from
the repository root. Shipped flat into the docs root that prefix has to
collapse rather than nest into /docs/docs/, which the resolver already did
via normalizeDocPath. Pinned with a test now that it is a shipped case
rather than an incidental one.

Both were read in full before shipping. Neither carries internal governance
content or credentials beyond the documented local dev defaults that are
already public in the repository.

Unresolvable intra-doc links are now 11 of 202, down from 23. Nine are
references to docs/architecture/ files that do not exist in the repository
at all, and two are the internal release-control documents deliberately
withheld from the shipped set.

Contract-Neutral: ships existing public documentation as static assets
2026-08-03 19:08:21 +01:00
rcourtman
29b9b324d9 Render shipped documentation in-app instead of serving raw markdown
Documentation links opened the raw .md asset, which browsers display as
plain text, so operators got markdown source complete with ## markers,
asterisks and unclickable [label](TARGET.md) syntax. Shipping the full set
made the content right without making it readable.

Add a viewer at /docs/<path> that renders the markdown. The raw asset stays
at /docs/<path>.md, which is what the viewer fetches, so nothing that wants
the source loses it, and the extensionless route cannot collide because
every shipped file ends in .md.

Notes on the pieces that are not obvious:

- The renderer is separate from the AI chat's. That one sets breaks: true
  globally, which would break every hard-wrapped paragraph in the shipped
  set, and pins hrefs to http/https/mailto, which would strip the relative
  links holding the documentation together. Options are passed per parse
  call so neither renderer disturbs the other. DOMPurify still gates output.
- Intra-doc links are rewritten to viewer routes and navigate in-app. Links
  climbing above the docs root, such as ../SECURITY.md, are clamped to it,
  because those files ship flat and the link only made sense on GitHub.
- A document that is not shipped does not 404. The static handler falls back
  to index.html for any unmatched non-API path including one ending in .md,
  so the viewer treats an HTML content type as missing rather than rendering
  the application shell as markdown.
- The route is public because the underlying markdown is already served
  unauthenticated. Gating the readable form would make it less reachable
  than its own source.
- Tables get their own scroll container and inline code is allowed to break,
  otherwise a wide table or a long URL pushes the whole page into horizontal
  scrolling on a phone. Verified by measuring scroll width at 390 pixels.

The doc URL constants now resolve to the viewer route, so the assertions
pinning the old .md paths were updated to match. That is the change being
made rather than a baseline being quietly moved.

Contract-Neutral: frontend rendering of existing static assets
2026-08-03 18:58:30 +01:00
rcourtman
164a9f92c6 Ship the documentation set the in-app docs index references
The in-app docs index listed 41 documents while only 9 were shipped, so
anything a self-hosted operator reached under /docs/ that was not one of
those 9 returned 404. Copy the 39 reachable documents from docs/ into
frontend-modern/public/docs so the set the index describes is actually
present offline, which is the point of shipping docs with a self-hosted
product rather than linking GitHub.

Deliberately not shipped: docs/release-control/v6/internal/
RELEASE_PROMOTION_POLICY.md and docs/releases/V6_PRERELEASE_RUNBOOK.md,
which are internal release governance rather than operator documentation.
Every shipped file was checked for GitHub blob/main links, which the sync
test forbids, and for internal-only content.

The sync test now derives its pairs from what is actually in public/docs
instead of a hand-maintained list, so a copied doc cannot silently drift
from its source and a new one cannot be added without one.

Known remaining gaps, all pre-existing: nine references to
docs/architecture/ files that do not exist in the repository, and parent
relative links such as ../SECURITY.md that resolve on GitHub but not under
the shipped /docs/ root.

Contract-Neutral: ships existing documentation as static assets
2026-08-03 18:24:53 +01:00
rcourtman
7f74e04be6 Ship the agent substrate doc the Settings panel links to
AGENT_SUBSTRATE_DOC_URL resolves to /docs/AGENT_SUBSTRATE.md and is
rendered as a link in AgentIntegrationsPanel, but the file was never
copied into frontend-modern/public/docs, so following it returned a 404.

Ship the doc and cover it in the sync test alongside the others.
2026-08-03 09:55:16 +01:00
rcourtman
daecc6d456 Sync shipped docs with the AI transparency link
17f113708 added the AI-Assisted Development entry to docs/README.md but
left the shipped copy under frontend-modern/public/docs untouched, so the
docs-sync test failed and Build and Test stayed red once the lint error in
front of it was cleared.

Copy the README across and ship AI_TRANSPARENCY.md too, otherwise the new
entry resolves to a missing /docs/AI_TRANSPARENCY.md in the in-app viewer.
Add the pair to the sync test so the two cannot drift again.

Contract-Neutral: shipped documentation sync, no contract delta
2026-08-03 09:54:28 +01:00
rcourtman
d4afbd1f9b Fix frontend bundle-size release gate 2026-06-14 13:23:10 +01:00
rcourtman
127e454834 Restore storage subtabs and guardrail headroom 2026-05-28 12:24:14 +01:00
rcourtman
3ff7c2f2e3 Replace v6 banner with guided welcome tour
Refs #1429
2026-04-19 21:26:54 +01:00
rcourtman
b402563ef1 Make self-hosted checkout return server-owned and recovery-only 2026-04-07 18:56:27 +01:00
rcourtman
ee847f727e test(frontend): guard against docs link drift 2026-03-28 20:08:34 +00:00
rcourtman
7a824337e6 fix(frontend): ship terms docs locally 2026-03-28 20:04:27 +00:00
rcourtman
0c4f7b3d43 docs(security): localize shipped doc self-link 2026-03-28 19:48:32 +00:00
rcourtman
44c529ba92 fix(frontend): localize security docs links 2026-03-28 19:30:24 +00:00
rcourtman
9b601f457c fix(frontend): ship telemetry disclosure docs locally 2026-03-28 18:19:52 +00:00