Skip to content

docs: record the stable fork/dev development and release branch - #342

Merged
omegent-app[bot] merged 9 commits into
fork/devfrom
docs/stable-dev-release-branch-handover
Aug 6, 2026
Merged

docs: record the stable fork/dev development and release branch#342
omegent-app[bot] merged 9 commits into
fork/devfrom
docs/stable-dev-release-branch-handover

Conversation

@patroza

@patroza patroza commented Aug 6, 2026

Copy link
Copy Markdown
Owner

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..a2ca89aa1 #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

opened by Patrick Roza in chat thread Discord · Discord · T3

@omegent-app omegent-app Bot changed the title docs: propose stable development and release branch docs: propose a stable fork/dev development and release branch Aug 6, 2026
@omegent-app
omegent-app Bot changed the base branch from fork/changes to fork/dev August 6, 2026 05:19
patroza added a commit that referenced this pull request Aug 6, 2026
First run of the provenance synchronization from
[#342](#342) — and the answer to
"get the latest upstream onto
`fork/dev`". Five upstream commits enter the product:

| | |
| --- | --- |
| `a2ca89aa` | feat: native subagent & workflow observability (pingdotgg#5219) |
| `990bb0b6` | fix: reconnect faster after remote server updates (pingdotgg#5404)
|
| `7251f1a1` | Prevent terminal loading flash (pingdotgg#5432) |
| `30e47153` | fix(web): preserve terminal font size when splitting
(pingdotgg#5444) |
| `de592a00` | Enrich terminal font previews (pingdotgg#5428) |

54 files, +7,055 / −175.

## Checkpoint

```json
{
  "importedCandidatesCommit": "9655a9ba955197361044ef6f8f97e35841ff779e",
  "importedCandidatesTree":   "50f9bfab717c30a8ea90d52060349e209502d116",
  "importedUpstreamCommit":   "a2ca89aa10f13a2222e08afd98c66285121d5ba2",
  "previousCandidatesTree":   "9b4cd3e1c774c3c436e43305c151edf596b2936a"
}
```

`previousCandidatesTree` is C1 from tag `fork-dev/2026-08-06.1`. Tag the
merge commit
`fork-dev/2026-08-06.2` with the values above once this lands.

## Two resolutions worth reviewing

Most of the 7 conflicted files are independent additions on both sides
and resolve as unions —
upstream's `backgroundLiveness` beside identity's
`originSource`/`participantSummaries`, upstream's
agent-spawn CTA rows beside the imported user-input Q&A timeline. Two
were not unions:

**`apps/web/src/components/Sidebar.logic.ts`** — the 3-way merge welded
upstream's
`hasPlanReadyPrompt` condition onto the `"Wake Required"` return body.
Left alone, a plan-ready
thread would render as **Wake Required** and no thread could ever reach
**Plan Ready**. Both
branches are restored with their own bodies. The status rank map is
merged onto upstream's new scale
with `Wake Required` at the `Working`/`Connecting` tier — its relative
position before the import.
**That tier placement is a judgement call; say if you want it ranked
differently.**

**`apps/mobile/src/lib/threadActivity.ts`** — upstream's
`isAgentInternalActivity` skip guard must
run *before* identity's resolved-user-input enrichment. The other order
enriches and pushes exactly
the agent-internal rows upstream means to drop.

## Validation

- All 12 `fork/candidates` commits replayed onto the rebuilt `fork/tim`;
`a2ca89aa1` confirmed an
  ancestor of the new candidates tip.
- No residual conflict markers; brace balance checked on the hand-edited
files.
- **Typecheck and tests have not run locally** — the rebase workspace
has no `node_modules`. Fork CI
on this PR is the first real verification. Do not merge on the strength
of this description.

## Provenance branches not yet pushed

`fork/base` → `4a73589` and `fork/tim` → `b1c5fa5` are rebased and
`fork/candidates` → `9655a9ba`
is rebuilt, but all three are **local only**. The ruleset *Protect
fork/tim, candidates, integration*
sets `non_fast_forward` with no bypass actor and the app token has no
`administration` scope, so I
cannot force-push them. Until they are pushed,
`importedCandidatesCommit` refers to a commit that
exists nowhere on the remote. The tree is what the delta depends on, but
the checkpoint is not fully
honest until that push happens.

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>
patroza added a commit that referenced this pull request Aug 6, 2026
Implements the split you asked for, without reintroducing
`fork/integration` and without any ops
change.

## The problem

`fork-ci`'s conclusion is what the smart-host poller promotes on — and
it also carried the mobile
release dispatch. So `ae4719b1c` passed all four required checks, failed
only at
`Dispatch Mobile Releases`, and stranded server, Discord, desktop and VS
Code deployment of the
entire upstream import. A release action could veto a validation
verdict.

## The split

| Workflow | Answers | Consumed by |
| --- | --- | --- |
| **Fork CI** | "is this SHA valid?" | the deploy poller, branch
protection |
| **Fork Release** (new) | "release this validated SHA" | nothing —
terminal |

Chained with `workflow_run`, which fires only after Fork CI **concludes
success** for a `push` on
`fork/dev`.

Against your four constraints:

- **Nothing released unless the SHA is green** — `workflow_run` gates on
`conclusion == 'success'`, and the `workflow_dispatch` escape hatch
re-checks it against the API
rather than trusting the operator. Releasing an unvalidated SHA by hand
is the one thing this split
  must not make easier.
- **Release breakage must not turn the SHA red** — the failure is
recorded against the release run.
  The poller queries `fork-ci.yml` runs and never sees it.
- **Releases follow the green verdict** — that is precisely
`workflow_run` ordering, rather than the
previous arrangement where dispatch raced the other jobs inside the same
run.
- **No `fork/integration`** — not needed, and the ops poller is
untouched.

## Two details worth reviewing

**Release scope compares against the last SHA _this workflow
released_**, not the last that merely
passed CI. Otherwise a commit whose release was skipped drops out of
scope permanently and its
changes are never represented in any release.

**Concurrency is keyed per SHA with `cancel-in-progress: false`.** Two
releases of different commits
may safely overlap, and cancelling a queued one would leave that commit
silently unreleased.

## Prerequisite: `fork/dev` must be the default branch

`workflow_run` only fires for workflow files present on the **repository
default branch**, which is
still `fork/changes`. Until that flips, this workflow will not trigger
and mobile releases must be
dispatched manually (`workflow_dispatch` with an exact SHA — the green
check still applies).

That was already Step 1 of
[#342](#342); this just gives it a
concrete forcing reason.

## Validation

- Both workflows parse; triggers and job sets confirmed:
`fork-ci` → `check, test, mobile_native_static_analysis, release_smoke`;
  `fork-release` → `release`.
- `vp fmt --check` clean.
- **The `workflow_run` chain is unexercised** and cannot be until the
default branch flips. The gate
logic and the green re-check are reviewable by reading; the trigger
itself is not yet proven. Worth
  watching the first merge after the flip.

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>
patroza added a commit that referenced this pull request Aug 6, 2026
Closes the overlay era. `fork/dev` was cut from the composed
`fork/integration` tip, so every
registered overlay's product content has been in `fork/dev` since the
cutover.

## Containment re-verified against the current tip

| Overlay | PR | Commits present in `fork/dev` |
| --- | --- | --- |
| `fork/identity` | #250 | 17 / 17 |
| `t3-discord/f7d37879-desktop-deeplinks` | #254 | 8 / 8 |
| `fork/discord` | #174 | 9 / 12 |
| `fork/vscode` | #175 | 2 / 3 |

The four that are not present touch **`pnpm-lock.yaml` only** — checked
by path, not by subject. They
are regeneration artifacts that compose discards by its own
`pnpm-lock.yaml -> theirs` rule and
replaces with its own lockfile commit. No product content sits outside
`fork/dev`.

## Change

- `integrationOverlays` emptied in `.github/pr-stack.json`.
- The matching `pull_request` bases dropped from `fork-ci.yml`, which
carried an explicit instruction
  to stay in sync with that list.

Overlay PRs #254, #174, #175 and #250 are closed alongside this. Leaving
them open against
`fork/changes` would duplicate their commits the next time anything
composes — the one ordering
hazard called out in [#342](#342).

## Scope

Deliberately narrow. The overlay machinery itself —
`compose-integration`,
`rebase-integration-overlays`, `force-update-overlay-tip`,
`client-overlay-ownership` and the
surrounding docs — is left in place. Removing it touches ~20 files and
is a separate decision; it
still passes its own tests with an empty manifest.

## Validation

- `fork-stack`, `rebase-pr-stack`, `compose-integration-overlays`,
`client-overlay-owner` and
`rebase-integration-overlays` suites: **69/69 pass** against the empty
manifest, so the tooling
  tolerates zero overlays rather than assuming at least one.
- `vp fmt --check` clean.

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 omegent-app Bot changed the title docs: propose a stable fork/dev development and release branch docs: record the stable fork/dev development and release branch Aug 6, 2026
github-actions Bot and others added 9 commits August 6, 2026 08:37
The proposal read as one large migration whose payoff arrived at the end. In
practice the benefit is concentrated in two steps — cut fork/dev from the green
fork/integration tip, and release exact green fork/dev SHAs — and everything
downstream of that is optional.

Restructure accordingly:

- Add an adopt-now/defer table so the blocking work is visible without reading
  the whole document.
- Promote the fork/dev cutover and release-from-fork/dev into named steps 1 and
  2, each a concrete checklist.
- Move clean downstream projection, tree-equivalence proofs, and periodic
  projection releases into a section marked deferred, and say plainly that
  nothing in steps 1-3 depends on them.
- State that provenance synchronization is a manual procedure to begin with;
  automating it is a convenience, not a prerequisite.
- Keep Source-* import trailers as immediate practice, since they are cheap at
  import time and hard to reconstruct later.

Call out the one ordering hazard explicitly: fork/dev is cut from
fork/integration, not fork/changes, so overlay content is present from the
first commit and every registered overlay must be drained rather than left open
against fork/changes.

Add an Ops Repository Changes section describing the prerequisite made
available in aaaomega/ops: the trusted deploy branch, CI workflow, and CI
trigger event become configurable with today's values as defaults, so the
cutover is a deploy.env edit and a poller restart, and reverting is the same
edit. Note that component checkpoint state keeps its filenames so the cutover
does not trigger a full fleet redeploy.

Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
The ops prerequisite section named the private ops repository and the
deployment host directly. Neither is needed to explain the change, and this
document lives in a public repository.

Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
Squash was listed as an open decision. It is decided: every PR into fork/dev
becomes exactly one commit. That is also what makes the rest of the document
hold together — the PR ledger maps one-to-one onto fork/dev history, release
scope is a diff between two commits, and a later clean projection has a single
unit to replay per PR.

Whether any exception is warranted is deliberately left open rather than
pre-specified; it can be argued when a concrete case appears. Until then squash
is the only merge method in practice, and step 1 now sets GitHub's default
merge method rather than relying on contributors picking the right button.

Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
The merge-policy section said to "set GitHub's repository default merge method"
and that leaving the other methods enabled was fine. There is no such field.
GitHub picks the merge button's primary action from whichever methods are
enabled, in the order merge commit then squash then rebase, so leaving merge
commits enabled would have left merge commit as the default and quietly
contradicted the decision.

Squash only becomes the default by disabling merge commits and rebase merging.
That also gives exceptions the right shape: taking one requires deliberately
re-enabling a method, rather than picking a different dropdown entry.

Also flag an ordering trap in step 1: required checks must not be configured
before CI is wired to run for fork/dev, or the PR that enables that CI can
never satisfy them.

Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
The branch page reports "5 commits behind pingdotgg/t3code:main" immediately
after a successful sync, and the count grows with every import. That is a
commit-graph artifact: the delta lands as one squashed commit, so fork/dev
carries upstream's content without upstream's commit objects, and GitHub
computes ahead/behind by reachability alone. Verified against the first real
sync — all five upstream commits' content is present in fork/dev and none of
them is an ancestor of it.

The dangerous part is the "Sync fork" button sitting next to that banner. It
merges upstream main into fork/dev, which is precisely the duplicate-history
failure this section already warns about for provenance tips, and the banner
invites it on every visit.

Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
The document claimed fork/dev could not carry upstream commits and that the
branch page would read N commits behind forever. That was wrong, and the
reasoning behind it was over-applied.

The no-merge rule protects against branches that are rebased: fork/base,
fork/tim and fork/candidates get new commit identities each cycle, so merging
their tips repeatedly duplicates history. upstream/main is append-only and its
identities are permanent, so nothing stops fork/dev from having them.

Importing only a tree delta brings upstream's content without its commit
objects, and GitHub measures ahead/behind by reachability alone — so the one
number worth reading was permanently wrong. Close the sync with
`git merge -s ours <upstream-tip>`, which keeps the tree byte-for-byte and adds
only the parent link. Verified against the current tip: tree unchanged at
5ce8e37, upstream a2ca89a becomes an ancestor, behind count 0.

State the hazard plainly: -s ours asserts every upstream change is accounted
for, so a resolution that silently dropped one makes that loss permanent. It
belongs at the end of a verified sync, never run alone to green the banner.

Configuration follows from wanting a merge commit without giving up squash.
Re-enabling merge commits repo-wide would make Merge the primary button again
— GitHub orders merge, squash, rebase — reversing the squash decision for every
ordinary PR. So keep squash-only and give the sync automation a ruleset bypass
actor to push the ancestry merge directly. The sync PR itself stays squashed;
the ancestry merge lands on top.

Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
The document still read as a plan with "do now" steps while the migration had
already been executed and, in places, executed differently. Rewrite it as the
record.

Corrected to match reality:

- fork/dev is the default branch, the contributor target and the release source,
  live since 2026-08-06, with the actual ruleset, checkpoint tags and SHAs named.
- Release now spans two workflows. fork-ci decides whether a SHA is valid and
  fork-release acts on that verdict via workflow_run, because a release action
  must never be able to veto a validation verdict.
- Ops parameterization and the deploy.env cutover are done, not pending.
- fork/changes and fork/integration are frozen, not fallbacks.
- Check selection is not path-inferred and the document no longer implies it is.
  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.

Adds what the cutover surfaced, because each item cost a round trip: fork/dev
had no CI path at all, mobile releases would have stopped silently, both mobile
workflows hardcoded fork/integration and rejected every fork/dev SHA, a release
failure could strand the fleet, and every PR based on fork/changes was already
broken by earlier rebases and needed its one real commit cherry-picked rather
than its branch replayed.

Open decisions are now the ones that are genuinely still open, and the migration
steps are the ones genuinely still outstanding.

Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
The overlays are drained and deregistered, but the instructions an agent or a
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) now says branch from fork/dev and target
fork/dev for every kind of work, names main, fork/changes and fork/integration
as bases never to use, and records that integrationOverlays is empty rather than
describing how to register one. The Discord bot's turn rules pointed recovery
branches at "the correct base (fork/discord overlay / fork/changes / etc.)" and
now point at fork/dev.

fork-stack.md, stack-ship-path.md and client-overlays.md describe the previous
operating model in detail. They are 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 in them that literally
instructed a base are corrected, so nothing in the repository still directs a PR
anywhere but fork/dev.

Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
@omegent-app
omegent-app Bot force-pushed the docs/stable-dev-release-branch-handover branch from 7556f09 to 88d47fd Compare August 6, 2026 08:39
@omegent-app
omegent-app Bot merged commit 65c3850 into fork/dev Aug 6, 2026
6 checks passed
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