Control: action.run lists created objects that show a publish late (cx-9ce.30)

Merged
TE
24d ago
+119-17

Summary

action.run sometimes answered with an empty created list, for example cmux tab new under load (plans/cmux-next/cli.md Remaining 13). The reply looks up each created object in the snapshot that reflects the run's daemon sequence. But the app can build a new object a publish after the event that moved the sequence, so the lookup came up empty.

  • A settled run now waits briefly for a snapshot that shows every object it created: at most 2 s, and always ending 100 ms before the request's own deadline. If an object never shows (say a tab that was opened and closed in the same run), it's left out, and the run still answers ran: true rather than timing out.
  • ControlSnapshotStore waits can now take any condition (snapshot(where:deadline:)); the sequence barrier uses the same path. The created-object wait lives on the store (ControlSnapshotStore+Created.swift), so ControlRouter doesn't grow.
  • A store wait whose deadline had already passed could register after its timer had fired, and then nothing ever resumed it. It now answers nil at once. The review found this; I couldn't write a test that hits the race reliably, so it is untested.
  • The bead's other half, item 8 (an unknown target reports ran: true), was already done: the router refuses an unknown target once the topology is loaded (ActionRunTargetTests), and ActionScope refuses an unknown tab, pane or workspace in the handler. cli.md now marks items 8 and 13 done.

Testing

Behavior tests ActionRunCreatedTests (CmuxNextControl). Each runs action.run through ControlRouter with an executor that creates a tab the way a loaded app can.

  1. The snapshot reaches the command's sequence first, and the tab appears 200 ms later. created must list it.
  2. The tab never appears, under the default 2 s request deadline. The run must answer ran: true with created: [].

All runs are fleet run-swift-testing-suites.sh on the full package:

  • Test 1, red (test only, 384a8010a12b): created was [].
  • Test 1, green (9df392c295d8): passes.
  • Test 2, red (test only, 8a5607051ff4, on the first fix): timeout after 1999 ms. The review predicted this: the first fix's wait ignored the request deadline.
  • Test 2, green (132b17e1fdd9, then 9d1559bf7863 with the race fix): both tests pass.

PasswordManagerRouteTests timed out in the four runs with the fix on the older base (73434cf13f4d). Its action succeeds and its 20 s wait for the Passwords tab expires. It never calls action.run or waits on the control snapshot store. #20103 documents the same fleet timeouts in it and in PinnedPageTests. On base it is skipped (no published same-tree cmux-tui), so base gives no comparison. On the merged head (1d96e462ec23, base merged with #20103), the full package run had no failing suite: PasswordManagerRouteTests ran (not skipped) and passed in 1 s, and both ActionRunCreatedTests pass.

Bead: cx-9ce.30

Changelog

  • Fixed: cmux commands that create something (for example cmux tab new) no longer sometimes report an empty created list.

🤖 Generated with Claude Code