diff --git a/docs/release-control/v6/internal/subsystems/security-privacy.md b/docs/release-control/v6/internal/subsystems/security-privacy.md
index 094f27ca3..816214038 100644
--- a/docs/release-control/v6/internal/subsystems/security-privacy.md
+++ b/docs/release-control/v6/internal/subsystems/security-privacy.md
@@ -96,6 +96,11 @@ evidence with no subsystem ownership.
That same governed home now also owns the single "usage data" vocabulary for
anonymous outbound telemetry and local-only upgrade events, so Pulse stops
describing those two privacy scopes as unrelated systems.
+That same operator-reporting boundary now also owns reusable latest-install
+adoption baselines. `scripts/telemetry_adoption_report.py` must emit
+windowed 24h, 72h, and 7d latest-install snapshots that split published
+versions from unpublished or development builds, so RC adoption reads stop
+depending on ad hoc SQL or one-off local helper scripts.
Security-facing settings remain intentionally shared with `frontend-primitives`
because shell framing and presentation consistency still belong there, but the
diff --git a/scripts/telemetry_adoption_report.py b/scripts/telemetry_adoption_report.py
index 4119d9841..f4a8c3bb3 100644
--- a/scripts/telemetry_adoption_report.py
+++ b/scripts/telemetry_adoption_report.py
@@ -23,6 +23,11 @@ from urllib.request import Request, urlopen
DEFAULT_DB_PATH = "/var/lib/pulse-license/licenses.sqlite"
DEFAULT_GITHUB_REPO = "rcourtman/Pulse"
+DEFAULT_LATEST_INSTALL_WINDOWS = (
+ ("24h", timedelta(hours=24)),
+ ("72h", timedelta(hours=72)),
+ ("7d", timedelta(days=7)),
+)
GIT_DESCRIBE_RE = re.compile(
r"^(?P\d+\.\d+\.\d+(?:-[0-9A-Za-z\.-]+)?)-(?P\d+)-g(?P[0-9a-fA-F]+)(?P-dirty)?$"
)
@@ -213,6 +218,51 @@ finally:
return json.loads(result.stdout)
+def counter_entries(counter: Counter[str], key_name: str) -> list[dict[str, Any]]:
+ return [
+ {key_name: value, "installs": installs}
+ for value, installs in sorted(counter.items(), key=lambda item: (-item[1], item[0]))
+ ]
+
+
+def summarize_latest_install_windows(
+ latest_by_install: dict[str, dict[str, Any]],
+ published_versions: set[str],
+ *,
+ now: datetime | None = None,
+ windows: tuple[tuple[str, timedelta], ...] = DEFAULT_LATEST_INSTALL_WINDOWS,
+) -> dict[str, Any]:
+ current_time = now or datetime.now(timezone.utc)
+ summary: dict[str, Any] = {}
+
+ for label, limit in windows:
+ version_split: Counter[str] = Counter()
+ published_split: Counter[str] = Counter()
+ non_release_split: Counter[str] = Counter()
+ platform_split: Counter[str] = Counter()
+
+ for row in latest_by_install.values():
+ received_at = parse_received_at(str(row["received_at"]))
+ if current_time - received_at > limit:
+ continue
+ platform = str(row.get("platform") or "unknown").strip() or "unknown"
+ identity = classify_reported_version(str(row.get("version") or ""), published_versions)
+ version_split[identity.version] += 1
+ platform_split[platform] += 1
+ target = published_split if identity.is_published_release else non_release_split
+ target[identity.version] += 1
+
+ summary[label] = {
+ "active_installs": sum(version_split.values()),
+ "latest_versions": counter_entries(version_split, "version"),
+ "published_versions": counter_entries(published_split, "version"),
+ "non_release_versions": counter_entries(non_release_split, "version"),
+ "platforms": counter_entries(platform_split, "platform"),
+ }
+
+ return summary
+
+
def summarize_rows(
db_stats: dict[str, Any],
rows: Iterable[dict[str, Any]],
@@ -225,50 +275,20 @@ def summarize_rows(
if existing is None or str(row["received_at"]) > str(existing["received_at"]):
latest_by_install[install_id] = row
- now = datetime.now(timezone.utc)
- active_24h = 0
- active_72h = 0
- platform_split = Counter()
- version_split = Counter()
- published_split = Counter()
- non_release_split = Counter()
-
- for row in latest_by_install.values():
- received_at = parse_received_at(str(row["received_at"]))
- age = now - received_at
- if age <= timedelta(hours=24):
- active_24h += 1
- if age <= timedelta(hours=72):
- active_72h += 1
- platform = str(row.get("platform") or "unknown").strip() or "unknown"
- platform_split[platform] += 1
- identity = classify_reported_version(str(row.get("version") or ""), published_versions)
- version_split[identity.version] += 1
- target = published_split if identity.is_published_release else non_release_split
- target[identity.version] += 1
+ latest_install_windows = summarize_latest_install_windows(latest_by_install, published_versions)
+ summary_72h = latest_install_windows["72h"]
return {
"db_stats": db_stats,
+ "latest_install_windows": latest_install_windows,
"active_latest": {
- "active_24h": active_24h,
- "active_72h": active_72h,
+ "active_24h": latest_install_windows["24h"]["active_installs"],
+ "active_72h": summary_72h["active_installs"],
},
- "latest_version_split_72h": [
- {"version": version, "installs": installs}
- for version, installs in sorted(version_split.items(), key=lambda item: (-item[1], item[0]))
- ],
- "published_version_split_72h": [
- {"version": version, "installs": installs}
- for version, installs in sorted(published_split.items(), key=lambda item: (-item[1], item[0]))
- ],
- "non_release_version_split_72h": [
- {"version": version, "installs": installs}
- for version, installs in sorted(non_release_split.items(), key=lambda item: (-item[1], item[0]))
- ],
- "latest_platform_split_72h": [
- {"platform": platform, "installs": installs}
- for platform, installs in sorted(platform_split.items(), key=lambda item: (-item[1], item[0]))
- ],
+ "latest_version_split_72h": summary_72h["latest_versions"],
+ "published_version_split_72h": summary_72h["published_versions"],
+ "non_release_version_split_72h": summary_72h["non_release_versions"],
+ "latest_platform_split_72h": summary_72h["platforms"],
}
@@ -280,30 +300,34 @@ def format_text(summary: dict[str, Any], repo: str, since_days: int) -> str:
f"latest ping: {summary['db_stats'].get('latest_ping') or 'unknown'}",
f"total rows: {summary['db_stats'].get('total_rows', 0)}",
f"total distinct installs: {summary['db_stats'].get('total_distinct_installs', 0)}",
- f"active installs (24h): {summary['active_latest']['active_24h']}",
- f"active installs (72h): {summary['active_latest']['active_72h']}",
- "",
- "Published versions (latest install state in last 72h):",
]
- published = summary["published_version_split_72h"]
- if published:
- lines.extend(f"- {entry['version']}: {entry['installs']}" for entry in published)
- else:
- lines.append("- none")
- lines.append("")
- lines.append("Non-release or unpublished versions (latest install state in last 72h):")
- non_release = summary["non_release_version_split_72h"]
- if non_release:
- lines.extend(f"- {entry['version']}: {entry['installs']}" for entry in non_release)
- else:
- lines.append("- none")
- lines.append("")
- lines.append("Platforms (latest install state in last 72h):")
- platform_split = summary["latest_platform_split_72h"]
- if platform_split:
- lines.extend(f"- {entry['platform']}: {entry['installs']}" for entry in platform_split)
- else:
- lines.append("- none")
+
+ for label, _ in DEFAULT_LATEST_INSTALL_WINDOWS:
+ window_summary = summary["latest_install_windows"][label]
+ lines.extend(
+ [
+ "",
+ f"Latest install state ({label}):",
+ f"- active installs: {window_summary['active_installs']}",
+ "- published versions:",
+ ]
+ )
+ if window_summary["published_versions"]:
+ lines.extend(f" - {entry['version']}: {entry['installs']}" for entry in window_summary["published_versions"])
+ else:
+ lines.append(" - none")
+ lines.append("- non-release or unpublished versions:")
+ if window_summary["non_release_versions"]:
+ lines.extend(
+ f" - {entry['version']}: {entry['installs']}" for entry in window_summary["non_release_versions"]
+ )
+ else:
+ lines.append(" - none")
+ lines.append("- platforms:")
+ if window_summary["platforms"]:
+ lines.extend(f" - {entry['platform']}: {entry['installs']}" for entry in window_summary["platforms"])
+ else:
+ lines.append(" - none")
return "\n".join(lines)
diff --git a/scripts/tests/test_telemetry_adoption_report.py b/scripts/tests/test_telemetry_adoption_report.py
index 091c4e515..9cafcb61c 100644
--- a/scripts/tests/test_telemetry_adoption_report.py
+++ b/scripts/tests/test_telemetry_adoption_report.py
@@ -79,6 +79,9 @@ class TelemetryAdoptionReportTest(unittest.TestCase):
self.assertEqual(summary["active_latest"]["active_24h"], 2)
self.assertEqual(summary["active_latest"]["active_72h"], 3)
+ self.assertEqual(summary["latest_install_windows"]["24h"]["active_installs"], 2)
+ self.assertEqual(summary["latest_install_windows"]["72h"]["active_installs"], 3)
+ self.assertEqual(summary["latest_install_windows"]["7d"]["active_installs"], 3)
self.assertEqual(
summary["published_version_split_72h"],
[{"version": "6.0.0-rc.1", "installs": 1}],
@@ -90,6 +93,61 @@ class TelemetryAdoptionReportTest(unittest.TestCase):
{"version": "6.0.0-rc.2", "installs": 1},
],
)
+ self.assertEqual(
+ summary["latest_install_windows"]["24h"]["published_versions"],
+ [{"version": "6.0.0-rc.1", "installs": 1}],
+ )
+ self.assertEqual(
+ summary["latest_install_windows"]["72h"]["non_release_versions"],
+ [
+ {"version": "0.0.0-feature-new-metric", "installs": 1},
+ {"version": "6.0.0-rc.2", "installs": 1},
+ ],
+ )
+ self.assertEqual(
+ summary["latest_install_windows"]["7d"]["platforms"],
+ [
+ {"platform": "binary", "installs": 2},
+ {"platform": "docker", "installs": 1},
+ ],
+ )
+
+ def test_format_text_includes_latest_install_windows(self) -> None:
+ summary = {
+ "db_stats": {
+ "latest_ping": "2026-04-14 10:04:08",
+ "total_rows": 3228,
+ "total_distinct_installs": 229,
+ },
+ "latest_install_windows": {
+ "24h": {
+ "active_installs": 127,
+ "published_versions": [{"version": "6.0.0-rc.1", "installs": 91}],
+ "non_release_versions": [{"version": "6.0.0-rc.2", "installs": 32}],
+ "platforms": [{"platform": "docker", "installs": 66}],
+ },
+ "72h": {
+ "active_installs": 153,
+ "published_versions": [{"version": "6.0.0-rc.1", "installs": 117}],
+ "non_release_versions": [{"version": "6.0.0-rc.2", "installs": 32}],
+ "platforms": [{"platform": "binary", "installs": 83}],
+ },
+ "7d": {
+ "active_installs": 157,
+ "published_versions": [{"version": "6.0.0-rc.1", "installs": 118}],
+ "non_release_versions": [{"version": "6.0.0-rc.2", "installs": 32}],
+ "platforms": [{"platform": "binary", "installs": 87}],
+ },
+ },
+ }
+
+ rendered = report.format_text(summary, "rcourtman/Pulse", 7)
+
+ self.assertIn("Latest install state (24h):", rendered)
+ self.assertIn("Latest install state (72h):", rendered)
+ self.assertIn("Latest install state (7d):", rendered)
+ self.assertIn(" - 6.0.0-rc.1: 118", rendered)
+ self.assertIn(" - 6.0.0-rc.2: 32", rendered)
if __name__ == "__main__":