Skip to content

build: keep every built file in a project group so Xcode reuses its build description - #14486

Merged
teamleaderleo merged 3 commits into
mainfrom
fix/pif-recovered-references
Sep 25, 2026
Merged

teamleaderleo merged 3 commits into
mainfrom
fix/pif-recovered-references

Conversation

@teamleaderleo

@teamleaderleo teamleaderleo commented Sep 25, 2026 •

Copy link
Copy Markdown
Collaborator

Every incremental cmux build, no-ops included, recreates Xcode's build description. The fleet measures that step at 32-35 s per build on cmux11s, about half of a 65-75 s no-op, and it doesn't change with the size of the edit.

Cause. Two files in the app's Sources phase belong to no group: MacDevicesComposition.swift (since 9401c25) and SurfaceCatalogSnapshot+DeviceVisibility.swift (since 6d5c49b). Xcode files such references under a synthesized "Recovered References" group whose GUID is new on every project load. The PIF therefore differs on every build, the build-description cache can never hit, and Xcode re-plans every time. This is the same failure #12976 fixed on 09-19.

Evidence.

  • xcodebuild -dumpPIF three times on an unchanged main tree gives three different hashes. The only differing leaves are that group's GUID and the signatures derived from it.
  • With this change, three dumps are byte-identical (736481854324a01c).
  • In run 36118886107 (the edit-loop benchmark on this branch's parent), 15 of 15 reload builds logged CreateBuildDescription with a new signature, while the xcodebuild invocations were identical.

Change.

  • Both file references now sit in the groups their siblings use (Sources, Sources/Surfaces), with paths relative to those groups.
  • New scripts/check-pbxproj-group-membership.py, run by check-pbxproj.sh, fails when a file a build phase lists belongs to no group. It flags exactly these two on current main and passes here.
  • Drops the dead CloudRequestClock.swift build-file and file-reference objects that refactor: move the Cloud services and values layer into a CmuxCloud package #14343 left behind. No phase or group referenced them.

check-pbxproj.sh, lint-pbxproj-test-wiring.sh and the three Python tests that reference check-pbxproj.sh pass. The wall-clock effect on reload builds gets measured next in the edit-loop benchmark.

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.


Summary by cubic

Keeps every built file in a project group so Xcode stops re-planning every no-op build. Two files in the Sources phase belonged to no group, so Xcode filed them under a synthesized "Recovered References" group with a new GUID on every load; the PIF then differed on every build, the build-description cache never hit, and no-op builds spent an extra 32-35 s re-planning. With this change, three -dumpPIF runs on an unchanged tree are byte-identical.

  • Moves MacDevicesComposition.swift into Sources and SurfaceCatalogSnapshot+DeviceVisibility.swift into Sources/Surfaces, with paths relative to those groups.
  • Adds scripts/check-pbxproj-group-membership.py, run by check-pbxproj.sh, that fails when a build-phase file is not reachable from the main group. The guard parses the project with normalize-pbxproj.py's tokenizer rather than a line regex, which missed space-indented objects, two objects on one line, and ids longer than 24 characters.
  • Registers the guard as non-product tooling and covers it in the normalizer tests.
  • Drops the dead CloudRequestClock.swift build-file and file-reference objects left behind by refactor: move the Cloud services and values layer into a CmuxCloud package #14343.

Written for commit cf20bda. Summary will update on new commits.

Review in cubic

…uild description

MacDevicesComposition.swift and SurfaceCatalogSnapshot+DeviceVisibility.swift were built but in no
group. Xcode files them under a synthesized Recovered References group with a new id on every load, so
the PIF differs on every build and the build description is recreated every time, no-ops included
(15 of 15 reload builds in run 36118886107 had a new signature with identical invocations; the fleet
measures that planning at 32-35 s per incremental build on cmux11s). Three -dumpPIF runs are now
byte-identical. scripts/check-pbxproj-group-membership.py (run by check-pbxproj.sh) fails on any built
file outside a group. Also drops the dead CloudRequestClock objects #14343 left behind.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 5 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used all 10 included reviews currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Repository: manaflow-ai/cmux/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: 6c6351b4-7cb6-41cc-b9b9-31e58619b7ec

📥 Commits

Reviewing files that changed from the base of the PR and between d2542e5 and cf20bda.

📒 Files selected for processing (7)
  • cmux.xcodeproj/project.pbxproj
  • scripts/check-pbxproj-group-membership.py
  • scripts/check-pbxproj.sh
  • scripts/ci/product_input_identity.py
  • scripts/verify-local.py
  • tests/test_normalize_pbxproj.py
  • tests/test_reuse_app_host_products.py

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

teamleaderleo and others added 2 commits September 25, 2026 06:39
The line regex skipped space-indented objects, a second object on one line
and ids longer than 24 characters, and counted a file as grouped when an
unreachable group held it. Parse the project with normalize-pbxproj.py's
tokenizer (the result matches plutil's) and walk the main group instead.
Register the guard as non-product tooling and cover it in the normalizer
tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@cursor

cursor Bot commented Sep 25, 2026

Copy link
Copy Markdown

Bugbot is paused — on-demand spend limit reached

Bugbot uses usage-based billing for this team and has hit its on-demand spend limit.

A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue.

@teamleaderleo
teamleaderleo merged commit 3d2478e into main Sep 25, 2026
123 of 136 checks passed
@teamleaderleo
teamleaderleo deleted the fix/pif-recovered-references branch September 25, 2026 12:42
@github-actions

Copy link
Copy Markdown
Contributor

Merge receipt for cf20bda571: every check was green at merge (12 verified; 14 skipped by policy). Full suite runs on main after merge.

rustybret pushed a commit to rustybret/bmux that referenced this pull request Sep 25, 2026
c055747 ci: parse runner expressions in the fork guard, and gate LINUX_RUNNER on fork PRs (manaflow-ai#14192)
fc112a8 docs(testing): describe how run-e2e.sh actually picks the runner (manaflow-ai#14620)
0f6edfa ci(owned): keep seeds until the disk is actually short, not at a fixed 6 (manaflow-ai#14621)
1b78097 CI: one owned-pool rescue sweeper instead of a rescue run per CI run (manaflow-ai#14602)
c7e79f6 Hold Files tree reloads while its context menu is open (manaflow-ai#14451)
dbb24cb ci: read the owned-pool rescue's Actions API through the route App (manaflow-ai#14499)
36b8063 ci: store each app-host product file once in the product archive (manaflow-ai#14601)
0dba677 CI: run CmuxWorkspaces package tests (manaflow-ai#14592)
2244e98 Fix color detection in native tmux mirrors (manaflow-ai#14175)
3d2478e build: keep every built file in a project group so Xcode reuses its build description (manaflow-ai#14486)
a1a5ae9 ci(cmux-tui): cache cargo builds in the Rust jobs (manaflow-ai#14613)
560e640 ci(owned): keep 8 seeds per mini and pick seeds by cost, not a 2-commit cap (manaflow-ai#14607)
561d317 cmux-debug-cli: find a publish-hq build in the HQ tag app cache (manaflow-ai#14579)
c0aaac7 fix(events): survive receive-timeout reconfiguration churn during replay (manaflow-ai#13888)
3bd994a fix: keep split zoom when the zoomed pane outlives a tab close (manaflow-ai#12853)
ca984c7 Session snapshots can send binding actions to ghostty on a surface that is no longer live (manaflow-ai#12623)
a47d65b settings: expose local tmux session persistence (manaflow-ai#13210)
e3acb25 ci: give an owned Mac's full app rebuild 35 minutes to compile (manaflow-ai#14594)

# Conflicts:
#	.github/workflows/ci-artifact-transport.yml
#	.github/workflows/ci-cache-receipts.yml
#	.github/workflows/ci-guards.yml
#	.github/workflows/ci-macos.yml
#	.github/workflows/ci-owned-pool-rescue.yml
#	.github/workflows/ci-web.yml
#	.github/workflows/ci.yml
#	.github/workflows/cloud-machine-tests.yml
#	.github/workflows/cloud-vm-guest-install.yml
#	.github/workflows/cloud-vm-image-contract.yml
#	.github/workflows/cloud-vm-image-reachability.yml
#	.github/workflows/cloudflare-relay.yml
#	.github/workflows/cmux-skill-contract.yml
#	.github/workflows/cmux-tui-sdks.yml
#	.github/workflows/cmux-tui-spec.yml
#	.github/workflows/cmux-tui.yml
#	.github/workflows/indexnow-tests.yml
#	.github/workflows/iroh-v2.yml
#	.github/workflows/localization-catalog.yml
#	.github/workflows/r2-upload-tests.yml
#	.github/workflows/remote-daemon.yml
#	.github/workflows/repair-nightly-appcast-content-types.yml
#	.github/workflows/required-checks-drift.yml
#	.github/workflows/resolve-dispatch-ref.yml
#	.github/workflows/seed-derived-data.yml
#	.github/workflows/terminal-hang-diagnostics.yml
#	.github/workflows/test-e2e.yml
#	.github/workflows/test-ios.yml
#	.github/workflows/testbox-broker-guard.yml
#	.github/workflows/web-validation.yml
teamleaderleo added a commit that referenced this pull request Sep 25, 2026
* test: the stale-run check must not read a GitHub API error as a head

On a rate limit `gh api --jq` prints the error body on stdout and exits
non-zero. The step's `|| true` kept that body as the current PR head, so
#14486's compile admission refused its own current run as stale (job
108058643725). This test fails until the step ignores non-SHA output.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* ci: ignore a GitHub API error in the stale-run check

`gh api --jq` prints an API error body on stdout, and `|| true` kept it, so
a rate limit made compile admission (and the remote-daemon admission) refuse
the PR's current run as stale. Treat anything but a 40-hex SHA as an
unresolved head, which already continues with normal CI.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test: give the remote-daemon stale-run test real head SHAs

The stale-run check now treats anything but a 40-hex SHA as an unresolved
head, so the placeholder heads "head" and "newer-head" read as unresolved
and the stale case passed. Use 40-hex values.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant