Stacked on #2725 (Split a manually linked pair when the API unlinks it). Until that merges this PR carries its commit too; only the last commit is new here. ## Problem `POST /api/resources/{id}/report-merge` (the drawer's "Split merged resource" dialog) excluded only the candidate IDs that `ResourceRegistry.SourceTargets` derives with `sourceSpecificID(mergedResource.Type, source, sourceID)`. For a source an operator link folded in, that candidate names neither side of the link: - an agent linked into a VM gets a `vm-` candidate; - an agent linked with a node or a Docker host gets a source-specific candidate, while the folded side's canonical ID derives from its machine ID. No `resource_links` row matched, so even with #2725's one-decision-per-pair store rule the link survived, the pair stayed merged on REST, `/api/state` and the websocket, and the API answered 200 "Merge reported" while the dialog toasted "Resource split applied". Two linked agents share their only source, so the API refused them as "Resource is not merged". Identity merges were already handled: `findMatch` checks exactly the candidate `SourceTargets` reports, and an agent/Docker pair merged by machine identity stays apart through three monitor rebuilds after report-merge. That is now pinned by a test. ## Fix - `applyManualLinks` records each link it applies on the merged resource (`recordManualLinkFold`, unexported `Resource.linkFolds`): the link row's own pair plus the sources the folded side brought, carrying the folded side's earlier folds so each link along a chain keeps its pair. - The record rides in-memory clones. The resources API seeds its registry from the monitor's already-linked listing and never holds the folded row, so this is the only place it can learn the pair. - `HandleReportMerge` excludes the pair of every link whose folded side brought a reported source (`ResourceRegistry.ManualLinkFolds`), alongside the existing identity-match exclusions, deduplicated in either order. #2725's `AddExclusion` then deletes the link row, so the pair splits from the monitor's next rebuild, as with unlink. An applied link also counts as a merge, so two linked agents can be reported. - A pair is recorded once. Record ingest can recreate a folded side whose source mapping points at a holder of another type, then fold it again. - A link joins only the pair its row names. Canonical-ID succession re-keys link endpoints with `UPDATE OR IGNORE` but moves `primary_id` unconditionally. A row whose re-key collided with the successor's own row therefore kept the retired endpoint and took the successor as its primary, and `applyManualLinks` merged the successor through it. No unlink or report-merge of the merged pair removed that row. A primary naming neither side now falls back to the row's first side, which leaves such a row inert. The drawer sends every merged source. Source categories are not attributed to individual contributors, so naming one that a folded side carried undoes that link. A source that arrived along a chain undoes every link on its way to the merged resource. ## Verification - `TestResourceReportMergeSplitsOperatorLinkedPair`: link and report-merge through the API handlers against a `MonitorAdapter` on the same SQLite store, rebuilt three times per step. Cases cover VM/agent, node/agent and agent/Docker pairs linked from either side, plus two linked agents. With #2725's handler, 6 of the 7 cases fail: five with "report-merge left 1 monitor resources", and the agent pair with a 400. The exception is a node linked from its agent, because the node's source-specific candidate happens to be its own ID. - `TestResourceReportMergeSplitsPairBehindASuccessionShadowedRow`, `TestResourceReportMergeSourceFilterSelectsLinks`, `TestResourceReportMergeSplitsIdentityMergedPair`, `TestContract_ResourceReportMergeReplacesOperatorLink` (response shape plus link removal), `TestManualLinkFoldsNameEachLinkPairAlongAChain` (monitor registry and a registry seeded from its listing), `TestManualLinkFoldsRecordEachPairOnceAcrossRecordIngests`, `TestManualLinkFoldRepeatedPairKeepsEarlierSources`, `TestCloneResource_CarriesLinkFolds`, and the `TestResourceAPIReportMergeExcludesRegistryLinkFolds` guardrail. - Negative controls, each failing at the expected assertion: the handler from #2725, the old not-merged gate, the primary honoured outside its row, folds appended without dedupe, a repeated pair keeping only its later sources, `applyManualLinks` without `recordManualLinkFold`, and a clone that shares the fold slice. - Full `./internal/unifiedresources/...`, `./internal/api/resourceapi/...`, `./internal/truenas/...` and `./internal/monitoring/...` pass.
Pulse documentation
Start here for installation, platform setup, security, operations, and Pulse Intelligence. Commands, configuration keys, image names, API fields, and product identifiers remain untranslated in localized guides.
Start here
- Install Pulse — signed Proxmox/Linux installation, Docker, Docker Compose, Kubernetes, and first-run setup.
- Production deployment and security — least-privilege Proxmox setup, root-agent boundaries, discovery, supply-chain verification, plan limits, scale evidence, and a rollout checklist.
- Upgrade from Pulse v5 — migration prerequisites, rollback, agent continuity, and post-upgrade checks.
- Releases and update channels: choosing Stable or Preview, beta and RC expectations, and how releases are tested and promoted.
- Configure Pulse — authentication, notifications, discovery, retention, and system settings.
- Deployment models — data locations, lifecycle, and differences between supported deployment paths.
- Troubleshooting and FAQ — common failures, diagnostics, and operator questions.
Localized getting started guides: Deutsch · Español
Platforms and agents
- Proxmox Backup Server
- Proxmox Mail Gateway
- Docker and Podman
- Kubernetes and Helm
- TrueNAS SCALE and CORE
- Unified Agent
- Agent security
- VM disk monitoring
- ZFS monitoring
- Temperature monitoring
VMware vSphere support is early access. Current builds expose dedicated vSphere inventory and recovery context, but operators should validate the integration against their own vCenter before production use.
Monitoring and operations
- Metrics history
- Recovery data
- Webhooks
- Automatic updates
- Centralized agent management (Pro)
- Operational trust model
- Current product screenshots
Pulse Intelligence
- Assistant, Patrol, and external-agent overview
- Patrol modes and safety
- Assistant safety model
- External agent HTTP and MCP substrate
Patrol watch-only analysis is available on Community with a local model or the operator's own provider. Investigation and governed fixes require the relevant Pulse Pro capabilities.
Security, privacy, and access
- Production deployment and security
- Security review scope
- Authentication and credential storage review packet
- Security guide
- Privacy and telemetry disclosure
- OIDC and SSO
- Proxy authentication
- Role-based access control (Pro)
- Audit logging (Pro)
- Reverse proxy configuration
- Code-signing policy
Plans and managed access
- Community, Relay, and Pro capabilities
- Relay and Pulse Mobile handoff
- Multi-tenant organizations (Enterprise/custom)
- Provider-hosted MSP operations (request-assisted)
Pulse Cloud is not generally available. Ordinary self-hosted Pulse remains the primary installation path; MSP and Enterprise access are explicit commercial paths rather than defaults in self-hosted setup.
Development and reference
Detailed design notes and dated migration specifications may remain in this directory for maintainers, but they are not operator setup guides unless they are linked from the sections above.
Previous versions and migrations
- Upgrade from v4 to v5
- Retired unified-navigation migration — historical context only; current Pulse uses platform-shaped navigation.
- Move a Pulse installation
Found a bug? Use the issue forms. For setup questions, use GitHub Discussions.