ci(fork): run Fork CI for fork/dev PRs and merges - #343
Merged
Conversation
fork/dev had no CI path at all: fork-ci.yml listed only the rebased stack layers and the registered overlays as pull_request bases, and had no push trigger anywhere. That blocks both halves of the cutover — PRs into fork/dev could not satisfy a required check, and no run would ever exist for a merge SHA. Add fork/dev as a pull_request base, and add a push trigger for it. The push run matters because fork/dev is never rebased, so its merge commits are the release candidates: deployment promotes an exact green SHA and keys on a successful run of this workflow for that SHA. A green PR tip is not enough when the merge SHA differs. Push runs are keyed by SHA and exempt from cancel-in-progress. Cancelling one as superseded would leave that merge SHA permanently unapprovable for deployment, which is not a state the poller can recover from on its own. Extend the release-tip jobs the same way. deployment_scope and dispatch_mobile_releases were gated on workflow_dispatch + fork/integration, so after the cutover mobile releases would have stopped silently — nothing errors, EAS simply never gets dispatched again. Both now accept a fork/dev push as well. The previous-successful-CI lookup that feeds classification hardcoded fork/integration + workflow_dispatch. Left alone it would diff every fork/dev push against an unrelated tip and classify every component as changed, so it now follows the running branch and event. The mobile dispatch likewise targets the branch being validated instead of a fixed fork/integration ref, so the mobile workflows come from the same tip that passed. Both fork/integration paths are retained unchanged; the two tips coexist until fork/integration is retired. Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
patroza
added a commit
that referenced
this pull request
Aug 6, 2026
Found by the first real `fork/dev` merge. [#343](#343) merged, the push run went green, `Dispatch Mobile Releases` fired — and then EAS production [failed](https://github.com/patroza/t3code/actions/runs/31074271669) at **Resolve approved integration source**. ## Cause Both mobile workflows check out a hardcoded ref and then assert containment: ```yaml ref: fork/integration # <- hardcoded ... git merge-base --is-ancestor "$target_sha" "$integration_sha" ``` A `fork/dev` SHA is not contained by `fork/integration`, so the assertion rejected it. Same class of hardcoding #343 fixed on the dispatch side — just one workflow further along, and only observable once a real `fork/dev` merge dispatched a release. ## Change - `release_branch` input on both mobile workflows, **defaulting to `fork/integration`** so any manual dispatch that omits it behaves exactly as before. - Checkout uses `${{ inputs.release_branch }}`; the "overlay deploy tooling" condition compares against it instead of the literal. - `fork-ci.yml` passes `release_branch` alongside the `--ref` it already passed. Passing one without the other is the trap worth naming: the workflow file would come from `fork/dev` while the product checkout stayed on `fork/integration` — precisely the failure above. ## Validation - All three workflow files parse; `release_branch` default confirmed as `fork/integration`. - `vp fmt --check` clean across `.github/workflows/`. - **The EAS path itself is not re-run by this PR.** Proof is the next `fork/dev` merge that classifies `mobile=true` — this PR's own merge should do it, since it touches `.github/workflows/**`. Worth watching that run rather than assuming. ## Note on the first dispatch That run classified every component as changed because no previous successful `fork/dev` push run existed to diff against — the documented conservative fallback. Subsequent merges diff against the prior green `fork/dev` SHA and should scope normally. Co-authored by [@patroza](https://github.com/patroza) opened by [Patrick Roza](https://discord.com/users/95218063095377920) in chat thread **Discord** · [Discord](https://discord.com/channels/1083767712431480922/1534783738322485399/1534783738322485399) · [T3](https://t3vm/?thread=584a9ad3-243e-4308-8a13-49acdd758b17) Co-authored-by: omegent-app[bot] <306514130+omegent-app[bot]@users.noreply.github.com> Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
omegent-app Bot
added a commit
that referenced
this pull request
Aug 6, 2026
Records the `fork/dev` development and release model — **adopted and live since 2026-08-06**. This started as a proposal; the migration then ran ahead of it, so the document is now the record rather than the plan. Documentation only. Every mechanism it describes is already merged and running. ## The model `fork/dev` is the default branch, the contributor target and the release source. It is never rebased. The provenance stack `main → fork/base → fork/tim → fork/candidates` stays rebased and feeds `fork/dev` through reviewed tree deltas, so contributor bases are never invalidated by an upstream update. | In place | | | --- | --- | | `fork/dev` cut from green `fork/integration` `21badd04e`, trees proven identical | tag `fork-dev/2026-08-06.1` | | Default branch, ruleset, squash-only, required checks | live | | CI for `fork/dev` PRs and merges | #343 | | Deployment promoting exact green `fork/dev` SHAs | ops `deploy.env` | | Validation and release split | #347, #349 | | First provenance sync, upstream `2a04db134..a2ca89a` | #345, tag `fork-dev/2026-08-06.2` | | Upstream ancestry recorded so "behind" reads true | `3a7e7a458` | | Overlays drained and deregistered | #348 | ## What this revision corrects The document had drifted from what was actually built: - **Release is two workflows, not one.** `fork-ci` decides whether a SHA is valid; `fork-release` acts on that verdict via `workflow_run`. A release action must never be able to veto a validation verdict — when mobile dispatch lived inside `fork-ci`, one failed EAS call marked a valid SHA unapprovable and stranded the whole fleet. - **Check selection is *not* path-inferred**, and the document previously implied it should be. Every PR runs all four required checks; only *release* scope is classified. A path filter that errs narrow silently skips a check on a protected branch, which is worse than a slightly slower suite. - **`fork/changes` and `fork/integration` are frozen**, not fallbacks. - Ops parameterization and the `deploy.env` cutover are **done**, not pending. - Steps that were "do now" are recorded as done, with real SHAs, tags and ruleset contents. ## What the cutover surfaced Added as a section, because each cost a round trip and the old path hid all of them: - `fork/dev` had **no CI path at all** — no `push` trigger, not listed as a `pull_request` base. - **Mobile releases would have stopped silently**; nothing errors when a gated job just never fires. - Both mobile workflows **hardcoded `ref: fork/integration`** and rejected every `fork/dev` SHA. - A release failure could **strand the fleet**. - **Every PR based on `fork/changes` was already broken** by earlier rebases — GitHub reported them as 60–100 commits and 629–741 files. Each was one commit of real work on stale history, fixed by cherry-picking that commit rather than replaying the branch. That last one is the clearest evidence for the whole premise: the old model was silently corrupting in-flight work, and nobody could see it. ## Deliberately not done Clean downstream projection is deferred indefinitely and nothing depends on it. Provenance sync stays manual. The overlay machinery is still present and still passes its tests with an empty manifest; removing it touches ~20 files and is a separate decision. ## Still open PRs #317, #226 and #185 conflict when cherry-picked onto `fork/dev`; #237 and #238 live in an external fork and need their author. `fork/changes` and `fork/integration` can be deleted once those are drained. ## Also: no guidance targets an overlay any more The overlays were drained in #348, but the instructions an agent or contributor actually reads before opening a PR still sent them at `fork/discord`, `fork/vscode`, `fork/identity`, the desktop deep-links branch, or `fork/changes`. Left alone, the next client-owned change would have been opened against a **closed overlay on a frozen branch**. - **`CLAUDE.md`** (`AGENTS.md` symlinks to it): branch from and target `fork/dev` for every kind of work; `main`, `fork/changes` and `fork/integration` named as bases never to use; the "register an `integrationOverlays` entry" instructions replaced with a record that it is empty. - **`apps/discord-bot/docs/agent-turn-rules.md`**: recovery branches pointed at *"the correct base (`fork/discord` overlay / `fork/changes` / etc.)"* → `fork/dev`. - **`fork-stack.md`, `stack-ship-path.md`, `client-overlays.md`**: bannered as superseded rather than rewritten — the provenance stack they document is still current and they are the record of how the fork worked before the cutover. The two lines that literally instructed a base are corrected. Verified by grep: nothing in the repository still directs a PR anywhere but `fork/dev`. ## Validation `vp fmt --check` clean; internal anchors checked. Documentation only — no code, tooling or workflow changes in this PR. Co-authored by [@patroza](https://github.com/patroza) opened by [Patrick Roza](https://discord.com/users/95218063095377920) in chat thread **Discord** · [Discord](https://discord.com/channels/1083767712431480922/1534783738322485399/1534783738322485399) · [T3](https://t3vm/?thread=584a9ad3-243e-4308-8a13-49acdd758b17) --------- Co-authored-by: T3 Code PR Stack <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: omegent-app[bot] <306514130+omegent-app[bot]@users.noreply.github.com> Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
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.
First PR against the new
fork/devbranch. Unblocks step 2 of#342.
Why
fork/devhad no CI path at all.fork-ci.ymllisted only the rebased stack layers and theregistered overlays as
pull_requestbases, and had nopush:trigger anywhere. That blocks bothhalves of the cutover:
fork/devcould never satisfy a required check.fork-ci.ymlrun for the exact SHA — would wait forever.What changed
fork/devadded as apull_requestbase.push:trigger forfork/dev.fork/devis never rebased, so its merge commits are therelease candidates; a green PR tip is not enough when the merge SHA differs.
cancel-in-progress. Cancelling one as supersededwould leave that merge SHA permanently unapprovable for deployment — a state the poller cannot
recover from on its own.
The quiet one: mobile releases
deployment_scopeanddispatch_mobile_releaseswere gated onworkflow_dispatch && refs/heads/fork/integration. After the cutover mobile releases would havestopped silently — nothing errors, EAS simply never gets dispatched again. Both now also accept a
fork/devpush.Two follow-on corrections that gate implies:
fork/integration+workflow_dispatch. Left alone it would diff everyfork/devpush against an unrelated tip andclassify every component as changed. It now follows the running branch and event.
--ref fork/integration. It now targets the branch beingvalidated, so the mobile workflows come from the same tip that passed.
Both
fork/integrationpaths are retained unchanged — the two tips coexist untilfork/integrationis retired.
Validation
vp fmt --checkclean.workflow_dispatch+checkout_ref(the same pattern thestack uses for tips that do not carry the workflow):
run 31073762042 — success.
Check✅Test✅Mobile Native Static Analysis✅Release Smoke✅.Classify Deployment ScopeandDispatch Mobile Releasescorrectly skipped, confirming thewidened
ifconditions do not fire on a non-release tip.fork/devpush path is still unexercised. It cannot be until this merges and somethinglands on
fork/dev; the first merge is the real proof. Worth watching that it produces a run andthat
Classify Deployment Scopepicks a sane previous SHA.Merge order
This must merge before required status checks are configured on
fork/dev. Requiring a checkthat cannot yet run would block the very PR that makes it runnable.
Co-authored by @patroza
opened by Patrick Roza in chat thread Discord · Discord · T3