Skip to content

docs(landing): correct the runbook against what the real run proved - #500

Merged
RonenMars merged 2 commits into
mainfrom
docs/landing-runbook-post-run-corrections
Aug 1, 2026
Merged

docs(landing): correct the runbook against what the real run proved#500
RonenMars merged 2 commits into
mainfrom
docs/landing-runbook-post-run-corrections

Conversation

@RonenMars

Copy link
Copy Markdown
Owner

The landing executed on 2026-08-01 as #497, #498 and #499.
All three slices merged with zero conflicts; the final tree comparison against the frozen prep snapshot came back with nine differing files, every one classified EXPECTED — no drift, nothing unexplained.
#457 is closed.

This turns the runbook from a plan into a record, and fixes the three claims the run disproved.
It targets land/integration-prep rather than main because that is where the live copy of the document is.

1. Guard B's enumeration must not be narrowed to $FORK..origin/main

This is the substantive one, and it is a latent safety defect rather than a stale number.

A companion document rewrote the guard's file enumeration as log --name-only $FORK..origin/main and expected it to reproduce the curated 21-file list.
It yields 8.
Seven of the eight hand-listed commits are ancestors of $FORK, so that range excludes them by construction.

The 15 files it drops include package.json, .github/workflows/test.yml, .github/workflows/deploy.yml and KICKOFF-landing-runbook.md — precisely the regressions fee27061 exists to undo and that slice A excludes by hand.
The guard meant to catch that class of mistake would have been blind to all of it.

The reason is structural and now stated in the document: prep's history is older than the fork, so a slice can revert main work that landed before the divergence point, not only after it.
Any enumeration bounded below by $FORK cannot see that class.
The curated list stays; the recipe is corrected.

Nothing slipped through on the real run, and that was checked rather than asserted: the wider 21-file guard was re-run retroactively across the whole landing, and every removed line is a genuine supersession (expo-mcp dropped by #489, test:e2e:mock rewritten by #470, the ship scripts moving their SENTRY_RELEASE exports, the Sentry investigation losing real org names by design, this document superseding its own text).
.github/workflows/deploy.yml, CLAUDE.md and docs/troubleshooting.md are additions only.

The CLAUDE.md case is written up with its mechanism: both slice B and slice C carried a copy predating #495, Guard B returned additions only on both (+16/−0 and +10/−0), and the reason is that git rebase applies patches rather than whole files, so non-overlapping hunks compose.
That was likely but never guaranteed — the guard is what turned it from an assumption into a fact.

2. #457 does not close itself

The old text said its diff shrinks as slices merge until it is empty and closes itself.
After all three slices merged it was still open, still reporting 73 changed files and +3446/−1126, while the tip-to-tip tree diff had drained to the nine EXPECTED files.

A PR's diff is computed against the merge-base, and every prep commit landed under a new SHA — slice A as a fresh cherry-pick, B and C as rebased replays — so nothing prep points at became reachable from main and the merge-base never moved.
Any PR whose content lands by replay rather than by merge must be closed by hand.

3. A --delete-branch needs its dependents enumerated first

New rule, stated generally: before deleting any branch on origin, list everything that depends on that ref — open PRs declaring it as their base branch included, not only things downstream of it in ancestry.

Ancestry-stacked is harmless; this run hit that case when land/slice-a was deleted before slice B needed it as a rebase base, and --onto origin/main $A_END is the same operation.

Base-ref-stacked is not.
GitHub closes such a PR automatically and the closure reads like ordinary cleanup.
The equivalent landing on the streamer repo hit this an hour earlier: the dependent PR was closed silently, its content dropped out of that landing, and the automation reported success.
The check is one gh pr list --json baseRefName command.

Also

  • The version-conflict path is marked still unexercised. main was ahead at 188/40 during the real run, but no slice touches app.json or android/app/build.gradle, so no conflict arose. It was not exercised by the rehearsal either and must not be read as proven.
  • The RNSentry note in the risks table is cleared — fix(ios): add RNSentry to the path-dependent Podfile.lock checksum list #495 closed that gap.
  • The rehearsal notes are now committed in-repo, so the section points at docs/landing/ rather than a path outside the repo.

Deliberately not included

sessionNames.test.ts still needs adding to the load-sensitive suite list in docs/troubleshooting.md.
That file lives on main, so it wants its own one-line PR there rather than being bundled into a prep-targeted change.
It is recorded as outstanding in the document.

…skip-ci]

The landing executed on 2026-08-01 as #497, #498 and #499 — all three slices merged with zero conflicts, and the final tree comparison came back with nine differing files, every one EXPECTED.
This records that outcome and fixes the three claims the run disproved.

Guard B's enumeration must not be narrowed to `$FORK..origin/main`.
Seven of the eight hand-listed commits are ancestors of the fork, so that range yields 8 files where the curated list yields 21, dropping `package.json`, both workflow files and `KICKOFF-landing-runbook.md` — precisely the regressions `fee27061` exists to undo and that slice A excludes by hand.
The reason is structural: prep's history is older than the fork, so a slice can revert `main` work that landed before the divergence point, and any enumeration bounded below by the fork is blind to that class.
Nothing slipped through on the run, and it was checked rather than assumed — the wider 21-file guard was re-run retroactively across the whole landing and every removed line is a genuine supersession.

PR #457 does not close itself.
A PR's diff is computed against the merge-base, and landing content by replay never moves it, so #457 sat open reporting 73 changed files after its content had fully landed.
It has to be closed by hand once the tip-to-tip diff is clean.

Adds a rule that any `--delete-branch` needs its dependents enumerated first, open PRs that declare the branch as their base included, not only things downstream of it in ancestry.
This run hit the harmless ancestry case when `land/slice-a` was deleted before slice B needed it as a rebase base.
The streamer landing hit the base-ref case an hour earlier: GitHub closed the dependent PR silently, its content dropped out of that landing, and the automation reported success.

Also records that the version-conflict path is still unexercised — `main` was ahead at 188/40 but no slice touched either version file — and clears the `RNSentry` note that #495 resolved.

[skip-ci]
…it [skip-ci]

The end-to-end check passed from `main` on a physical iPhone 17 Pro, but only after three false starts the Verification section did not warn about.

A bare `npx expo run:ios --device` cannot sign this app on a physical device.
Xcode's automatic signing regenerates its own Team Provisioning Profile every build and ignores hand-made ones, so the profile never carries App Groups and the build dies during "Planning build" with six errors and xcodebuild exit 65.
That is exactly the failure #480 exists to solve, and it ships `scripts/dev-device.sh` for it — the six errors mean the wrong command was used, not that signing regressed.
The existing block is right for a simulator, and only its `<simulator-udid>` placeholder said so.

The other two faults arrived together and are independent, which matters because either can occur alone.

The first is that a Metro already listening on 8081 captures the device.
`expo run:ios` is non-interactive here, so it answers its own port-conflict prompt with `Skipping dev server`, and the device attaches to whatever already owns the port — on this run a server rooted at the repo root on `land/integration-prep` rather than the worktree under test.
This is the dangerous one precisely because it is silent: with a healthy bundler it produces a working app showing another branch's code, and the log reports success.
The remedy is to check the port owner before trusting the result and to confirm the bundle root in the Metro log.

The second is that a long-lived Metro's resolver cache goes stale when its tree is rewritten underneath it.
That server had been running for eight hours across the whole landing and could no longer resolve `react/jsx-runtime`, which was present on disk in both trees the entire time.
This has nothing to do with which branch is served — it reproduces on the correct branch, with no mismatch to point at — so it is documented as its own failure with `--clear` as the fix.

Both were visible in one red screen, and only the module path in the error revealed that the tree was also wrong.
Recording them as one story would send the next reader hunting a branch-contamination bug that does not exist.

[skip-ci]
@RonenMars
RonenMars force-pushed the docs/landing-runbook-post-run-corrections branch from acdd00c to 78b7be5 Compare August 1, 2026 22:10
@RonenMars
RonenMars changed the base branch from land/integration-prep to main August 1, 2026 22:10
@RonenMars
RonenMars merged commit f719d7b into main Aug 1, 2026
20 of 28 checks passed
@RonenMars
RonenMars deleted the docs/landing-runbook-post-run-corrections branch August 1, 2026 22:16
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