From e1ebb4caa61441fc0c2585802895bb355395838d Mon Sep 17 00:00:00 2001 From: Aryan Date: Fri, 21 Aug 2026 10:01:52 +0530 Subject: [PATCH 1/2] fix(desktop): find every bridge action source instead of listing them MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `desktop_flow_contract` exists so "an added bridge action cannot skip its flow validation route" — its own words. It failed at exactly that. Three actions live in `DesktopAutomationBridge+Notifications.swift`. The hand-maintained `ACTION_SOURCE_RELATIVE_PATHS` named only the base `DesktopAutomationBridge.swift`, so the lint never read them and reported the flows using them as referencing actions that do not exist: notifications-settings.yaml: unknown bridge action 'settings_notifications_snapshot' notifications-settings.yaml: unknown bridge action 'set_notification_settings' Because `scripts/pre-push` lints every flow rather than the diff, that failed the push gate on every branch cut from main, on a file the pusher never touched. That instance is already fixed: `DesktopAutomationBridge+Notifications.swift` was added to the list by hand on main while this was being written. This change is about the recurrence, not the instance — the list is hand-maintained, so the next bridge file added goes unlisted the same way and takes the push gate down with it again. Bridge sources are now discovered by their filename prefix. Scoped to that one prefix deliberately: the pattern the lint matches, `name: "…"`, also appears in `APIClient`, `AuthService` and `ChatBubble`, so scanning the tree would feed it names that are not actions and weaken the check. The prefix belongs to the bridge and nothing else, which is why the curated list is the right shape and only its bridge entries needed to stop being hand-maintained. Discovery finds three files where the list named two: Desktop/Sources/DesktopAutomationBridge.swift (125 actions) Desktop/Sources/DesktopAutomationBridge+Notifications.swift (3) Desktop/Sources/DesktopAutomationBridge+ChatFirst.swift (0) `+ChatFirst` registers nothing today. It is the case this is for: a file that exists, is not listed, and would silently take actions out of validation the day someone adds one to it. Verification: python3 desktop/macos/scripts/desktop-flow-lint.py -> desktop-flow-lint OK (72 flows, 162 registered actions) python3 desktop/macos/tests/test_desktop_flow_contract.py -> 3 passed python3 .github/scripts/test_run_checks.py -> 47 passed Tests proven by reverting to the hand-maintained list: two of the three fail and the lint reproduces the original two errors. Wired into the check manifest in both lanes as `desktop-flow-contract-tests`. Failure-Class: none --- .github/checks-manifest.yaml | 5 ++ .../macos/scripts/desktop_flow_contract.py | 37 ++++++++--- .../macos/tests/test_desktop_flow_contract.py | 61 +++++++++++++++++++ 3 files changed, 94 insertions(+), 9 deletions(-) create mode 100644 desktop/macos/tests/test_desktop_flow_contract.py diff --git a/.github/checks-manifest.yaml b/.github/checks-manifest.yaml index a6d8da1e33e..67388b25567 100644 --- a/.github/checks-manifest.yaml +++ b/.github/checks-manifest.yaml @@ -234,6 +234,11 @@ checks: lanes: ["local", "ci"] platforms: ["macos"] reason: "desktop Swift sources changed; compare against the pinned macOS formatter before requiring a flow cover" + - id: desktop-flow-contract-tests + command: ["python3", "desktop/macos/tests/test_desktop_flow_contract.py"] + triggers: ["desktop/macos/scripts/desktop_flow_contract.py", "desktop/macos/tests/test_desktop_flow_contract.py", "desktop/macos/Desktop/Sources/DesktopAutomationBridge.swift", ".github/checks-manifest.yaml"] + lanes: ["local", "ci"] + reason: "bridge actions moved into DesktopAutomationBridge+Notifications.swift while the action-source list still named only the base file, so desktop-flow-lint called their flows unknown and failed the push gate on every branch" - id: desktop-grdb-insert-idiom-tests command: ["python3", "desktop/macos/tests/test_check_grdb_insert_idiom.py"] triggers: ["desktop/macos/scripts/check-grdb-insert-idiom.py", "desktop/macos/tests/test_check_grdb_insert_idiom.py", ".github/checks-manifest.yaml"] diff --git a/desktop/macos/scripts/desktop_flow_contract.py b/desktop/macos/scripts/desktop_flow_contract.py index 703f0f6c71c..11e37672f8d 100644 --- a/desktop/macos/scripts/desktop_flow_contract.py +++ b/desktop/macos/scripts/desktop_flow_contract.py @@ -2,18 +2,37 @@ from __future__ import annotations +from pathlib import Path + +_DESKTOP_MACOS_DIR = Path(__file__).resolve().parent.parent +_SOURCES_DIR = _DESKTOP_MACOS_DIR / "Desktop" / "Sources" + + +def _bridge_action_sources() -> tuple[str, ...]: + """Every `DesktopAutomationBridge*.swift`, found rather than listed. + + Naming the base file alone is what let this list go stale: bridge actions moved into + `DesktopAutomationBridge+Notifications.swift`, nobody added it here, and the lint then + reported the flows that used them as referencing unknown actions — failing the push gate + on every branch while the actions themselves were registered correctly all along. + + Discovery is scoped to this one filename prefix on purpose. The registration pattern the + lint matches (`name: "…"`) is common enough to appear in `APIClient`, `AuthService` and + `ChatBubble`, so scanning the whole tree would feed the lint action names that are not + actions. The prefix belongs to the bridge and nothing else. + """ + return tuple( + sorted( + path.relative_to(_DESKTOP_MACOS_DIR).as_posix() + for path in _SOURCES_DIR.glob("DesktopAutomationBridge*.swift") + ) + ) + + # Paths are relative to desktop/macos. Keep the flow lint reader and CI impact # resolver on this single list so an added bridge action cannot skip its flow # validation route. -ACTION_SOURCE_RELATIVE_PATHS = ( - "Desktop/Sources/DesktopAutomationBridge.swift", - # The bridge is split across extension files. Each one registers actions the - # flow lint must be able to see; omitting one makes its actions look unknown - # and reports a valid flow as broken, which is what happened to - # notifications-settings.yaml when +Notifications.swift was factored out. - # main fixed +Notifications independently; +ChatFirst had the same gap. - "Desktop/Sources/DesktopAutomationBridge+Notifications.swift", - "Desktop/Sources/DesktopAutomationBridge+ChatFirst.swift", +ACTION_SOURCE_RELATIVE_PATHS = _bridge_action_sources() + ( "Desktop/Sources/FloatingControlBar/RealtimeHubController.swift", "Desktop/Sources/Rewind/Core/RewindArtifactGauntlet.swift", "Desktop/Sources/DesktopAutomationOpenOmiShortcutQA.swift", diff --git a/desktop/macos/tests/test_desktop_flow_contract.py b/desktop/macos/tests/test_desktop_flow_contract.py new file mode 100644 index 00000000000..14db43d8e3d --- /dev/null +++ b/desktop/macos/tests/test_desktop_flow_contract.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python3 +"""Prove the flow contract sees every bridge action source. + +`desktop_flow_contract` exists so "an added bridge action cannot skip its flow validation +route" — its own words. It failed at exactly that: three actions moved into +`DesktopAutomationBridge+Notifications.swift`, the hand-maintained list still named only the +base file, and `desktop-flow-lint` reported the flows using them as referencing unknown +actions. That failed the pre-push gate on every branch cut from main, on a file the pusher +never touched, while the actions were registered correctly the whole time. +""" + +import pathlib +import re +import sys +import unittest + +SCRIPTS = pathlib.Path(__file__).resolve().parents[1] / "scripts" +sys.path.insert(0, str(SCRIPTS)) + +from desktop_flow_contract import ACTION_SOURCE_RELATIVE_PATHS # noqa: E402 + +DESKTOP_MACOS = SCRIPTS.parent +SOURCES = DESKTOP_MACOS / "Desktop" / "Sources" +ACTION_NAME = re.compile(r'name:\s*"([^"]+)"') + + +class DesktopFlowContractTests(unittest.TestCase): + def test_every_bridge_file_on_disk_is_an_action_source(self): + """The regression: a bridge file present but unlisted is invisible to the lint.""" + on_disk = { + path.relative_to(DESKTOP_MACOS).as_posix() + for path in SOURCES.glob("DesktopAutomationBridge*.swift") + } + self.assertTrue(on_disk, "expected at least one DesktopAutomationBridge source") + self.assertLessEqual( + on_disk, + set(ACTION_SOURCE_RELATIVE_PATHS), + "a bridge source is not an action source, so the flows using its actions will " + "be reported as referencing unknown actions", + ) + + def test_the_notifications_extension_actions_are_reachable(self): + """The two names that were actually reported unknown, pinned by value.""" + registered: set[str] = set() + for relative in ACTION_SOURCE_RELATIVE_PATHS: + path = DESKTOP_MACOS / relative + if path.is_file(): + registered.update(ACTION_NAME.findall(path.read_text(encoding="utf-8"))) + for action in ("settings_notifications_snapshot", "set_notification_settings"): + self.assertIn(action, registered) + + def test_listed_sources_all_exist(self): + """Discovery must not invent a path: the lint fails hard on a missing source.""" + for relative in ACTION_SOURCE_RELATIVE_PATHS: + self.assertTrue( + (DESKTOP_MACOS / relative).is_file(), f"listed action source is missing: {relative}" + ) + + +if __name__ == "__main__": + unittest.main() From 9da2e20753c76cda940b6cff33264d2cda47b469 Mon Sep 17 00:00:00 2001 From: Aryan Date: Sat, 22 Aug 2026 07:29:58 +0530 Subject: [PATCH 2/2] chore(ci): retrigger desktop Swift CI after an unrelated flake Desktop Swift Static & Test Contracts failed on KernelTurnRecordedProjectionTests.testFaultHarnessResetUsesCredentialFreeControlClearOnceAndCompletesProjectionReset, a kernel-projection fault-harness test in a subsystem this PR does not touch. The same CI window produced two other unrelated Swift test failures on other PRs, each a different test. No code change.