fix(ios): stop committing path-dependent Podfile.lock checksums - #469
Merged
Conversation
ExpoModulesCore, ExpoWidgets and hermes-engine generate their podspecs at install time and bake the checkout's absolute path into them (HERMES_CLI_PATH, the precompiled ExpoModulesCore tarball file:// URL, the ExpoWidgets bundle copy script). A pod's SPEC CHECKSUM is the SHA1 of its generated podspec, so those three values are a function of where the repo is checked out and differ for every worktree, machine and CI runner. bundle exec pins the COCOAPODS: line but does nothing for these, so ios/Podfile.lock kept ping-ponging between whoever ran pod install last — the usual source of ExpoWidgets/hermes-engine conflicts on rebases. Add scripts/reset-podfile-lock-path-noise.sh, which reverts ios/Podfile.lock when those three lines are the only drift, and run it right after pod install in the ship script, the deploy workflow and the native dev reset. A genuine pod change also moves that pod's version line, so real drift is left alone.
RonenMars
added a commit
that referenced
this pull request
Aug 1, 2026
Follow-up to #469. `npm run dev:reset` was the last bare `pod install` left in the repo. Without `bundle exec` it resolves a Homebrew CocoaPods instead of the Gemfile-pinned 1.16.2 and rewrites the `COCOAPODS:` line in `ios/Podfile.lock` — exactly what the pin exists to prevent, and what #455 set out to fix everywhere else. It now also runs `scripts/reset-podfile-lock-path-noise.sh` afterwards, matching `ship-ios.sh`, `dev-tunnel-native-reset.sh` and the deploy workflow, so a full dev reset leaves the lockfile clean instead of carrying this checkout's path-dependent checksums. The remaining bare `pod install` mentions in the repo are all inside historical docs (`docs/upgrade-to-expo-56.md`, `docs/research/`, runbooks) describing past sessions, so they are left alone.
RonenMars
added a commit
that referenced
this pull request
Aug 1, 2026
## Why The runbook described itself as a "live procedure — edit it as PRs land", but the chain it sequenced is gone. Verified 2026-08-01 — every PR it orchestrated is `CLOSED` with `mergedAt=null`, i.e. **closed, not merged**: ``` #339 #341 #343 #345 #346 #347 #353 #354 #355 #356 #357 #358 #359 #360 #361 #362 #363 #364 #368 #372 #373 #376 #385 #386 #387 ``` The work reached `main` through the integration branch instead, and the PRs were closed as redundant. The integration branch the runbook treated as proof the set could coexist, `integration-dev/v1.0.0-2026-07-22`, has been deleted. That invalidates the phase order, the per-PR loop, the pre-flight sweep, the decision to close `#355`, the conflict **A–I** resolutions, and the definition of done. The only PR row still accurate is `#291`, which is still open and still excluded by standing request. ## What changed The body becomes a tombstone: what the runbook was for, what actually happened, and a table pointing at where each still-true trap now lives. The file is kept rather than deleted so inbound links resolve and nobody rebuilds the same plan from the merge report. Two of its four traps were already in `docs/troubleshooting.md` (the `.claude/` worktree gotcha and serial `SessionScreen` verification). The other two are lifted there now under a new "CI signals" section, because both are repo-wide facts rather than properties of those branches: - a `[skip-ci]` head commit reports every required context green in seconds having run nothing - a stacked PR (base ≠ `main`) still gets full CI here, since `test.yml`'s `pull_request` trigger has no `branches:` filter Conflict **J** is obsolete for a separate reason: those `ios/Podfile.lock` checksums encode the checkout's absolute path, so resolving it was never meaningful. #469 added `scripts/reset-podfile-lock-path-noise.sh`, which drops that drift. ## Two live findings, one already fixed The runbook's `[skip-ci]` section claimed the required contexts were `Type check`, `Unit tests`, `Integration tests`, `Lint`. The ruleset actually required **only `Lint` and `Type check`** — unit and integration tests could not block a merge at all, which makes the `[skip-ci]` trap worse than documented, not better. Its one outstanding post-merge action (add `i18n` to required checks, never done since #368) is now complete: `Unit tests`, `Integration tests` and `i18n` were added to the `main` ruleset on 2026-08-01. Confirmed safe first — all three report `pass` on a real `chore/bump-**` version-bump PR (#472), so the deploy pipeline's bumps are not deadlocked. Note: `.github/workflows/test.yml:25` carries the same wrong claim about which contexts are required. Left alone here to keep this docs-only.
RonenMars
added a commit
that referenced
this pull request
Aug 1, 2026
…dates (#488) Dependabot's #460 rebased from `main` onto `land/integration-prep`, so it lands with the rest of the integration work. Bumps `@modelcontextprotocol/sdk` 1.29.0 to 1.30.0, `fast-uri` 3.1.2 to 3.1.5 and `hono` 4.12.25 to 4.12.33, all dev-only transitive dependencies, with `package.json` untouched. The PR title advertises `@hono/node-server` 1.19.14 to 2.0.12 carrying GHSA-9mqv-5hh9-4cgg, but the diff does not do that. The SDK bump widens the declared range from `^1.19.9` to `^1.19.9 || ^2.0.5`, and widening a range does not move a pin that already satisfies it, so `@hono/node-server` stays at 1.19.14. That advisory never reached the shipped app because the package is dev-only; taking the fix is a separate `npm update` that this bump newly makes possible. `npm ci` produced no further lockfile drift, and `bundle exec pod install` moved only the three path-dependent SPEC CHECKSUM lines documented in #469, so `ios/Podfile.lock` is deliberately excluded.
RonenMars
added a commit
that referenced
this pull request
Aug 1, 2026
…ver (#489) Expo MCP is now configured at user scope as `expo-local` for both Claude Code and Codex, which makes the per-project install redundant rather than merely unused. `expo-mcp` was a devDependency whose only consumer was the `expo_local` server in `.codex/config.toml`, invoked by relative path as `./node_modules/.bin/expo-mcp`, so the package and that entry go together. It pulled in `@expo/mcp-tunnel`, `@modelcontextprotocol/sdk`, `@hono/node-server`, `hono` and `fast-uri` — 829 lockfile lines and roughly 38 MB of `node_modules` that nothing else declares and no source file imports. It was also the origin of the churn in #488; every package that PR bumped is removed here. `AGENTS.md` and `CLAUDE.md` record the global setup so the dependency does not get re-added: it attaches to a local Metro dev server on `http://127.0.0.1:8081`, it is for screenshots, device logs and simulator verification, and remote tunneling via `--mcp-server-url` / `@expo/mcp-tunnel` is not to be used unless asked. Nothing shipped is affected — the subtree was dev-only, never entered the bundle, and was never invoked by an npm script or CI job. `bundle exec pod install` moved only the three path-dependent SPEC CHECKSUM lines documented in #469, so `ios/Podfile.lock` is deliberately excluded.
RonenMars
added a commit
that referenced
this pull request
Aug 1, 2026
…dates (#488) Dependabot's #460 rebased from `main` onto `land/integration-prep`, so it lands with the rest of the integration work. Bumps `@modelcontextprotocol/sdk` 1.29.0 to 1.30.0, `fast-uri` 3.1.2 to 3.1.5 and `hono` 4.12.25 to 4.12.33, all dev-only transitive dependencies, with `package.json` untouched. The PR title advertises `@hono/node-server` 1.19.14 to 2.0.12 carrying GHSA-9mqv-5hh9-4cgg, but the diff does not do that. The SDK bump widens the declared range from `^1.19.9` to `^1.19.9 || ^2.0.5`, and widening a range does not move a pin that already satisfies it, so `@hono/node-server` stays at 1.19.14. That advisory never reached the shipped app because the package is dev-only; taking the fix is a separate `npm update` that this bump newly makes possible. `npm ci` produced no further lockfile drift, and `bundle exec pod install` moved only the three path-dependent SPEC CHECKSUM lines documented in #469, so `ios/Podfile.lock` is deliberately excluded.
RonenMars
added a commit
that referenced
this pull request
Aug 1, 2026
…ver (#489) Expo MCP is now configured at user scope as `expo-local` for both Claude Code and Codex, which makes the per-project install redundant rather than merely unused. `expo-mcp` was a devDependency whose only consumer was the `expo_local` server in `.codex/config.toml`, invoked by relative path as `./node_modules/.bin/expo-mcp`, so the package and that entry go together. It pulled in `@expo/mcp-tunnel`, `@modelcontextprotocol/sdk`, `@hono/node-server`, `hono` and `fast-uri` — 829 lockfile lines and roughly 38 MB of `node_modules` that nothing else declares and no source file imports. It was also the origin of the churn in #488; every package that PR bumped is removed here. `AGENTS.md` and `CLAUDE.md` record the global setup so the dependency does not get re-added: it attaches to a local Metro dev server on `http://127.0.0.1:8081`, it is for screenshots, device logs and simulator verification, and remote tunneling via `--mcp-server-url` / `@expo/mcp-tunnel` is not to be used unless asked. Nothing shipped is affected — the subtree was dev-only, never entered the bundle, and was never invoked by an npm script or CI job. `bundle exec pod install` moved only the three path-dependent SPEC CHECKSUM lines documented in #469, so `ios/Podfile.lock` is deliberately excluded.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
bundle exec pod installrewrites threeSPEC CHECKSUMentries inios/Podfile.lockon every machine, and they never converge.A pod's
SPEC CHECKSUMis the SHA1 of its generated podspec, and exactly three pods bake the checkout's absolute path into theirs:hermes-engineHERMES_CLI_PATH→…/node_modules/hermes-compiler/hermesc/osx-bin/hermescExpoModulesCorefile:///…/expo-modules-core/prebuilds/output/debug/…tar.gz, plus the same path insideprepare_commandExpoWidgets…/node_modules/expo-widgets/ios/../bundle/build/ExpoWidgets.bundleVerified locally: the SHA1 of each
Pods/Local Podspecs/<pod>.podspec.jsonequals the value inPodfile.lock, and rewriting only the repo path changes all three and nothing else.So the committed values can only ever match one checkout path.
git log -- ios/Podfile.lockshows the ping-pong exactly as predicted:github-actions[bot]commits (the runner's checkout path) alternating with local commits, flipping those three lines each time.This also corrects the premise of #455.
bundle execdoes pin theCOCOAPODS:line, but it cannot stabilise these three — they are a function of the path, not of the CocoaPods version.What changed
scripts/reset-podfile-lock-path-noise.shrevertsios/Podfile.lockwhen those three lines are the only drift, and runs right afterpod installinscripts/ship-ios.sh, the deploy workflow, andscripts/dev-tunnel-native-reset.sh.Real drift is left alone: a genuine pod change also moves that pod's version line, so the diff is never limited to those three checksums.
This keeps
land-version-bump.shand the deploy job'sNEED_LOCKcheck working unchanged — they simply stop seeing a dirty lockfile when nothing real moved.CLAUDE.mdnow describes the actual cause instead of attributing the churn to barepod install.Verification
npm run test:scripts— 59 passed, including 4 new cases (noise-only reverts, mixed drift preserved, staged noise reverted, clean lockfile is a no-op).ios/Podfile.lock: mutating only the three checksums is reverted; mutatingReachabilitySwiftalongside them is preserved.npm run lint— 0 errors.deploy.ymlparses;bash -nclean on all three touched scripts.