ci(fork): report the full release scope, not just mobile - #349

Merged
patroza merged 1 commit into
fork/devfrom
fork-dev/release-summary-scope
Aug 6, 2026
Merged

ci(fork): report the full release scope, not just mobile#349
patroza merged 1 commit into
fork/devfrom
fork-dev/release-summary-scope

Conversation

@omegent-app

Copy link
Copy Markdown

The release summary asserted that server, Discord, desktop and VS Code are promoted by the poller,
but never said whether this SHA actually selects any of them. The one question worth asking — what
does this release move — still needed a trip to the smart host.

Change

Classify all seven keys instead of only mobile, using scripts/classify-deployment-diff.shthe
same script the poller runs
, so the report and the fleet cannot disagree about what a diff means.

The summary now renders, against the previous released SHA:

TargetSelectedPromoted by
Server (restart)yessmart-host poller
Discord botyessmart-host poller
Desktopyessmart-host poller
VS Codeyessmart-host poller
Mobile (EAS)yesthis workflow

Plus the diffed range, the classification basis, a collapsed changed-file list, and:

  • web_hot_swap shown on the server row, because it changes promotion from a restart to a bundle
    swap — a materially different operation to read as "server: yes".
  • A non-runtime-only range called out explicitly, rather than five silent no rows that look like a
    bug.

Verified against real ranges, not by reading

RangeResult
21badd04e..a5ff7e40c (upstream import, 37 runtime paths)deploy=true, every target selected
3a7e7a458..a5ff7e40c (workflow files only)deploy=false, nothing promoted

The caveat, stated in the summary itself

The poller diffs against the last SHA it actually deployed, which is not always the last
released SHA — a promotion it skipped, or one that failed part-way, leaves its baseline behind this
one. When they diverge the poller selects a superset of the reported rows, never a subset, so the
table cannot claim a target is moving when it is not. That direction is the safe one, and it is
written into the summary rather than left for someone to rediscover.

Making it exact would mean reading poller state that lives on the smart host and is not reachable
from CI, so the report is honest about being a faithful re-computation rather than a mirror.

Co-authored by @patroza

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

The release summary asserted that server, Discord, desktop and VS Code are
promoted by the poller but never said whether this SHA actually selects any of
them, so the one question worth asking — what does this release move — needed a
trip to the smart host to answer.
Classify all seven keys instead of only mobile, using
scripts/classify-deployment-diff.sh: the same script the poller runs, so the
report and the fleet cannot disagree about what a diff means. Render a table of
every target against the previous released SHA, note web_hot_swap on the server
row because it changes promotion from a restart to a bundle swap, and call out a
non-runtime-only range explicitly rather than showing five silent "no" rows.
Verified against real ranges rather than by reading. 21badd0..a5ff7e4 (the
upstream import, 37 runtime paths) reports every target selected;
3a7e7a4..a5ff7e4 (workflow files only) reports deploy=false and nothing
promoted.
The caveat is stated in the summary rather than left implicit: the poller diffs
against the last SHA it actually deployed, which is not always the last released
SHA, because a skipped or partly failed promotion leaves its baseline behind.
When they diverge the poller selects a superset of the reported rows, never a
subset, so the table cannot claim a target is moving when it is not.
Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
@patroza
patroza merged commit 885f127 into fork/devAug 6, 2026
5 checks passed
omegent-appBot 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>
Sign up for freeto 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

@patroza
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

ci(fork): report the full release scope, not just mobile - #349

Merged
patroza merged 1 commit into
fork/devfrom
fork-dev/release-summary-scope
Aug 6, 2026
Merged

ci(fork): report the full release scope, not just mobile#349
patroza merged 1 commit into
fork/devfrom
fork-dev/release-summary-scope

Conversation

@omegent-app

Copy link
Copy Markdown

The release summary asserted that server, Discord, desktop and VS Code are promoted by the poller,
but never said whether this SHA actually selects any of them. The one question worth asking — what
does this release move — still needed a trip to the smart host.

Change

Classify all seven keys instead of only mobile, using scripts/classify-deployment-diff.shthe
same script the poller runs
, so the report and the fleet cannot disagree about what a diff means.

The summary now renders, against the previous released SHA:

TargetSelectedPromoted by
Server (restart)yessmart-host poller
Discord botyessmart-host poller
Desktopyessmart-host poller
VS Codeyessmart-host poller
Mobile (EAS)yesthis workflow

Plus the diffed range, the classification basis, a collapsed changed-file list, and:

  • web_hot_swap shown on the server row, because it changes promotion from a restart to a bundle
    swap — a materially different operation to read as "server: yes".
  • A non-runtime-only range called out explicitly, rather than five silent no rows that look like a
    bug.

Verified against real ranges, not by reading

RangeResult
21badd04e..a5ff7e40c (upstream import, 37 runtime paths)deploy=true, every target selected
3a7e7a458..a5ff7e40c (workflow files only)deploy=false, nothing promoted

The caveat, stated in the summary itself

The poller diffs against the last SHA it actually deployed, which is not always the last
released SHA — a promotion it skipped, or one that failed part-way, leaves its baseline behind this
one. When they diverge the poller selects a superset of the reported rows, never a subset, so the
table cannot claim a target is moving when it is not. That direction is the safe one, and it is
written into the summary rather than left for someone to rediscover.

Making it exact would mean reading poller state that lives on the smart host and is not reachable
from CI, so the report is honest about being a faithful re-computation rather than a mirror.

Co-authored by @patroza

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

The release summary asserted that server, Discord, desktop and VS Code are
promoted by the poller but never said whether this SHA actually selects any of
them, so the one question worth asking — what does this release move — needed a
trip to the smart host to answer.
Classify all seven keys instead of only mobile, using
scripts/classify-deployment-diff.sh: the same script the poller runs, so the
report and the fleet cannot disagree about what a diff means. Render a table of
every target against the previous released SHA, note web_hot_swap on the server
row because it changes promotion from a restart to a bundle swap, and call out a
non-runtime-only range explicitly rather than showing five silent "no" rows.
Verified against real ranges rather than by reading. 21badd0..a5ff7e4 (the
upstream import, 37 runtime paths) reports every target selected;
3a7e7a4..a5ff7e4 (workflow files only) reports deploy=false and nothing
promoted.
The caveat is stated in the summary rather than left implicit: the poller diffs
against the last SHA it actually deployed, which is not always the last released
SHA, because a skipped or partly failed promotion leaves its baseline behind.
When they diverge the poller selects a superset of the reported rows, never a
subset, so the table cannot claim a target is moving when it is not.
Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
@patroza
patroza merged commit 885f127 into fork/devAug 6, 2026
5 checks passed
omegent-appBot 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>
Sign up for freeto 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

@patroza
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

ci(fork): report the full release scope, not just mobile - #349

Merged
patroza merged 1 commit into
fork/devfrom
fork-dev/release-summary-scope
Aug 6, 2026
Merged

ci(fork): report the full release scope, not just mobile#349
patroza merged 1 commit into
fork/devfrom
fork-dev/release-summary-scope

Conversation

@omegent-app

Copy link
Copy Markdown

The release summary asserted that server, Discord, desktop and VS Code are promoted by the poller,
but never said whether this SHA actually selects any of them. The one question worth asking — what
does this release move — still needed a trip to the smart host.

Change

Classify all seven keys instead of only mobile, using scripts/classify-deployment-diff.shthe
same script the poller runs
, so the report and the fleet cannot disagree about what a diff means.

The summary now renders, against the previous released SHA:

TargetSelectedPromoted by
Server (restart)yessmart-host poller
Discord botyessmart-host poller
Desktopyessmart-host poller
VS Codeyessmart-host poller
Mobile (EAS)yesthis workflow

Plus the diffed range, the classification basis, a collapsed changed-file list, and:

  • web_hot_swap shown on the server row, because it changes promotion from a restart to a bundle
    swap — a materially different operation to read as "server: yes".
  • A non-runtime-only range called out explicitly, rather than five silent no rows that look like a
    bug.

Verified against real ranges, not by reading

RangeResult
21badd04e..a5ff7e40c (upstream import, 37 runtime paths)deploy=true, every target selected
3a7e7a458..a5ff7e40c (workflow files only)deploy=false, nothing promoted

The caveat, stated in the summary itself

The poller diffs against the last SHA it actually deployed, which is not always the last
released SHA — a promotion it skipped, or one that failed part-way, leaves its baseline behind this
one. When they diverge the poller selects a superset of the reported rows, never a subset, so the
table cannot claim a target is moving when it is not. That direction is the safe one, and it is
written into the summary rather than left for someone to rediscover.

Making it exact would mean reading poller state that lives on the smart host and is not reachable
from CI, so the report is honest about being a faithful re-computation rather than a mirror.

Co-authored by @patroza

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

The release summary asserted that server, Discord, desktop and VS Code are
promoted by the poller but never said whether this SHA actually selects any of
them, so the one question worth asking — what does this release move — needed a
trip to the smart host to answer.
Classify all seven keys instead of only mobile, using
scripts/classify-deployment-diff.sh: the same script the poller runs, so the
report and the fleet cannot disagree about what a diff means. Render a table of
every target against the previous released SHA, note web_hot_swap on the server
row because it changes promotion from a restart to a bundle swap, and call out a
non-runtime-only range explicitly rather than showing five silent "no" rows.
Verified against real ranges rather than by reading. 21badd0..a5ff7e4 (the
upstream import, 37 runtime paths) reports every target selected;
3a7e7a4..a5ff7e4 (workflow files only) reports deploy=false and nothing
promoted.
The caveat is stated in the summary rather than left implicit: the poller diffs
against the last SHA it actually deployed, which is not always the last released
SHA, because a skipped or partly failed promotion leaves its baseline behind.
When they diverge the poller selects a superset of the reported rows, never a
subset, so the table cannot claim a target is moving when it is not.
Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
@patroza
patroza merged commit 885f127 into fork/devAug 6, 2026
5 checks passed
omegent-appBot 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>
Sign up for freeto 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

@patroza
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

ci(fork): report the full release scope, not just mobile - #349

Merged
patroza merged 1 commit into
fork/devfrom
fork-dev/release-summary-scope
Aug 6, 2026
Merged

ci(fork): report the full release scope, not just mobile#349
patroza merged 1 commit into
fork/devfrom
fork-dev/release-summary-scope

Conversation

@omegent-app

Copy link
Copy Markdown

The release summary asserted that server, Discord, desktop and VS Code are promoted by the poller,
but never said whether this SHA actually selects any of them. The one question worth asking — what
does this release move — still needed a trip to the smart host.

Change

Classify all seven keys instead of only mobile, using scripts/classify-deployment-diff.shthe
same script the poller runs
, so the report and the fleet cannot disagree about what a diff means.

The summary now renders, against the previous released SHA:

TargetSelectedPromoted by
Server (restart)yessmart-host poller
Discord botyessmart-host poller
Desktopyessmart-host poller
VS Codeyessmart-host poller
Mobile (EAS)yesthis workflow

Plus the diffed range, the classification basis, a collapsed changed-file list, and:

  • web_hot_swap shown on the server row, because it changes promotion from a restart to a bundle
    swap — a materially different operation to read as "server: yes".
  • A non-runtime-only range called out explicitly, rather than five silent no rows that look like a
    bug.

Verified against real ranges, not by reading

RangeResult
21badd04e..a5ff7e40c (upstream import, 37 runtime paths)deploy=true, every target selected
3a7e7a458..a5ff7e40c (workflow files only)deploy=false, nothing promoted

The caveat, stated in the summary itself

The poller diffs against the last SHA it actually deployed, which is not always the last
released SHA — a promotion it skipped, or one that failed part-way, leaves its baseline behind this
one. When they diverge the poller selects a superset of the reported rows, never a subset, so the
table cannot claim a target is moving when it is not. That direction is the safe one, and it is
written into the summary rather than left for someone to rediscover.

Making it exact would mean reading poller state that lives on the smart host and is not reachable
from CI, so the report is honest about being a faithful re-computation rather than a mirror.

Co-authored by @patroza

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

The release summary asserted that server, Discord, desktop and VS Code are
promoted by the poller but never said whether this SHA actually selects any of
them, so the one question worth asking — what does this release move — needed a
trip to the smart host to answer.
Classify all seven keys instead of only mobile, using
scripts/classify-deployment-diff.sh: the same script the poller runs, so the
report and the fleet cannot disagree about what a diff means. Render a table of
every target against the previous released SHA, note web_hot_swap on the server
row because it changes promotion from a restart to a bundle swap, and call out a
non-runtime-only range explicitly rather than showing five silent "no" rows.
Verified against real ranges rather than by reading. 21badd0..a5ff7e4 (the
upstream import, 37 runtime paths) reports every target selected;
3a7e7a4..a5ff7e4 (workflow files only) reports deploy=false and nothing
promoted.
The caveat is stated in the summary rather than left implicit: the poller diffs
against the last SHA it actually deployed, which is not always the last released
SHA, because a skipped or partly failed promotion leaves its baseline behind.
When they diverge the poller selects a superset of the reported rows, never a
subset, so the table cannot claim a target is moving when it is not.
Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
@patroza
patroza merged commit 885f127 into fork/devAug 6, 2026
5 checks passed
omegent-appBot 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>
Sign up for freeto 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

@patroza
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

ci(fork): report the full release scope, not just mobile - #349

Merged
patroza merged 1 commit into
fork/devfrom
fork-dev/release-summary-scope
Aug 6, 2026
Merged

ci(fork): report the full release scope, not just mobile#349
patroza merged 1 commit into
fork/devfrom
fork-dev/release-summary-scope

Conversation

@omegent-app

Copy link
Copy Markdown

The release summary asserted that server, Discord, desktop and VS Code are promoted by the poller,
but never said whether this SHA actually selects any of them. The one question worth asking — what
does this release move — still needed a trip to the smart host.

Change

Classify all seven keys instead of only mobile, using scripts/classify-deployment-diff.shthe
same script the poller runs
, so the report and the fleet cannot disagree about what a diff means.

The summary now renders, against the previous released SHA:

TargetSelectedPromoted by
Server (restart)yessmart-host poller
Discord botyessmart-host poller
Desktopyessmart-host poller
VS Codeyessmart-host poller
Mobile (EAS)yesthis workflow

Plus the diffed range, the classification basis, a collapsed changed-file list, and:

  • web_hot_swap shown on the server row, because it changes promotion from a restart to a bundle
    swap — a materially different operation to read as "server: yes".
  • A non-runtime-only range called out explicitly, rather than five silent no rows that look like a
    bug.

Verified against real ranges, not by reading

RangeResult
21badd04e..a5ff7e40c (upstream import, 37 runtime paths)deploy=true, every target selected
3a7e7a458..a5ff7e40c (workflow files only)deploy=false, nothing promoted

The caveat, stated in the summary itself

The poller diffs against the last SHA it actually deployed, which is not always the last
released SHA — a promotion it skipped, or one that failed part-way, leaves its baseline behind this
one. When they diverge the poller selects a superset of the reported rows, never a subset, so the
table cannot claim a target is moving when it is not. That direction is the safe one, and it is
written into the summary rather than left for someone to rediscover.

Making it exact would mean reading poller state that lives on the smart host and is not reachable
from CI, so the report is honest about being a faithful re-computation rather than a mirror.

Co-authored by @patroza

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

The release summary asserted that server, Discord, desktop and VS Code are
promoted by the poller but never said whether this SHA actually selects any of
them, so the one question worth asking — what does this release move — needed a
trip to the smart host to answer.
Classify all seven keys instead of only mobile, using
scripts/classify-deployment-diff.sh: the same script the poller runs, so the
report and the fleet cannot disagree about what a diff means. Render a table of
every target against the previous released SHA, note web_hot_swap on the server
row because it changes promotion from a restart to a bundle swap, and call out a
non-runtime-only range explicitly rather than showing five silent "no" rows.
Verified against real ranges rather than by reading. 21badd0..a5ff7e4 (the
upstream import, 37 runtime paths) reports every target selected;
3a7e7a4..a5ff7e4 (workflow files only) reports deploy=false and nothing
promoted.
The caveat is stated in the summary rather than left implicit: the poller diffs
against the last SHA it actually deployed, which is not always the last released
SHA, because a skipped or partly failed promotion leaves its baseline behind.
When they diverge the poller selects a superset of the reported rows, never a
subset, so the table cannot claim a target is moving when it is not.
Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
@patroza
patroza merged commit 885f127 into fork/devAug 6, 2026
5 checks passed
omegent-appBot 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>
Sign up for freeto 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

@patroza
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

ci(fork): report the full release scope, not just mobile - #349

Merged
patroza merged 1 commit into
fork/devfrom
fork-dev/release-summary-scope
Aug 6, 2026
Merged

ci(fork): report the full release scope, not just mobile#349
patroza merged 1 commit into
fork/devfrom
fork-dev/release-summary-scope

Conversation

@omegent-app

Copy link
Copy Markdown

The release summary asserted that server, Discord, desktop and VS Code are promoted by the poller,
but never said whether this SHA actually selects any of them. The one question worth asking — what
does this release move — still needed a trip to the smart host.

Change

Classify all seven keys instead of only mobile, using scripts/classify-deployment-diff.shthe
same script the poller runs
, so the report and the fleet cannot disagree about what a diff means.

The summary now renders, against the previous released SHA:

TargetSelectedPromoted by
Server (restart)yessmart-host poller
Discord botyessmart-host poller
Desktopyessmart-host poller
VS Codeyessmart-host poller
Mobile (EAS)yesthis workflow

Plus the diffed range, the classification basis, a collapsed changed-file list, and:

  • web_hot_swap shown on the server row, because it changes promotion from a restart to a bundle
    swap — a materially different operation to read as "server: yes".
  • A non-runtime-only range called out explicitly, rather than five silent no rows that look like a
    bug.

Verified against real ranges, not by reading

RangeResult
21badd04e..a5ff7e40c (upstream import, 37 runtime paths)deploy=true, every target selected
3a7e7a458..a5ff7e40c (workflow files only)deploy=false, nothing promoted

The caveat, stated in the summary itself

The poller diffs against the last SHA it actually deployed, which is not always the last
released SHA — a promotion it skipped, or one that failed part-way, leaves its baseline behind this
one. When they diverge the poller selects a superset of the reported rows, never a subset, so the
table cannot claim a target is moving when it is not. That direction is the safe one, and it is
written into the summary rather than left for someone to rediscover.

Making it exact would mean reading poller state that lives on the smart host and is not reachable
from CI, so the report is honest about being a faithful re-computation rather than a mirror.

Co-authored by @patroza

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

The release summary asserted that server, Discord, desktop and VS Code are
promoted by the poller but never said whether this SHA actually selects any of
them, so the one question worth asking — what does this release move — needed a
trip to the smart host to answer.
Classify all seven keys instead of only mobile, using
scripts/classify-deployment-diff.sh: the same script the poller runs, so the
report and the fleet cannot disagree about what a diff means. Render a table of
every target against the previous released SHA, note web_hot_swap on the server
row because it changes promotion from a restart to a bundle swap, and call out a
non-runtime-only range explicitly rather than showing five silent "no" rows.
Verified against real ranges rather than by reading. 21badd0..a5ff7e4 (the
upstream import, 37 runtime paths) reports every target selected;
3a7e7a4..a5ff7e4 (workflow files only) reports deploy=false and nothing
promoted.
The caveat is stated in the summary rather than left implicit: the poller diffs
against the last SHA it actually deployed, which is not always the last released
SHA, because a skipped or partly failed promotion leaves its baseline behind.
When they diverge the poller selects a superset of the reported rows, never a
subset, so the table cannot claim a target is moving when it is not.
Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
@patroza
patroza merged commit 885f127 into fork/devAug 6, 2026
5 checks passed
omegent-appBot 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>
Sign up for freeto 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

@patroza
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

ci(fork): report the full release scope, not just mobile - #349

Merged
patroza merged 1 commit into
fork/devfrom
fork-dev/release-summary-scope
Aug 6, 2026
Merged

ci(fork): report the full release scope, not just mobile#349
patroza merged 1 commit into
fork/devfrom
fork-dev/release-summary-scope

Conversation

@omegent-app

Copy link
Copy Markdown

The release summary asserted that server, Discord, desktop and VS Code are promoted by the poller,
but never said whether this SHA actually selects any of them. The one question worth asking — what
does this release move — still needed a trip to the smart host.

Change

Classify all seven keys instead of only mobile, using scripts/classify-deployment-diff.shthe
same script the poller runs
, so the report and the fleet cannot disagree about what a diff means.

The summary now renders, against the previous released SHA:

TargetSelectedPromoted by
Server (restart)yessmart-host poller
Discord botyessmart-host poller
Desktopyessmart-host poller
VS Codeyessmart-host poller
Mobile (EAS)yesthis workflow

Plus the diffed range, the classification basis, a collapsed changed-file list, and:

  • web_hot_swap shown on the server row, because it changes promotion from a restart to a bundle
    swap — a materially different operation to read as "server: yes".
  • A non-runtime-only range called out explicitly, rather than five silent no rows that look like a
    bug.

Verified against real ranges, not by reading

RangeResult
21badd04e..a5ff7e40c (upstream import, 37 runtime paths)deploy=true, every target selected
3a7e7a458..a5ff7e40c (workflow files only)deploy=false, nothing promoted

The caveat, stated in the summary itself

The poller diffs against the last SHA it actually deployed, which is not always the last
released SHA — a promotion it skipped, or one that failed part-way, leaves its baseline behind this
one. When they diverge the poller selects a superset of the reported rows, never a subset, so the
table cannot claim a target is moving when it is not. That direction is the safe one, and it is
written into the summary rather than left for someone to rediscover.

Making it exact would mean reading poller state that lives on the smart host and is not reachable
from CI, so the report is honest about being a faithful re-computation rather than a mirror.

Co-authored by @patroza

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

The release summary asserted that server, Discord, desktop and VS Code are
promoted by the poller but never said whether this SHA actually selects any of
them, so the one question worth asking — what does this release move — needed a
trip to the smart host to answer.
Classify all seven keys instead of only mobile, using
scripts/classify-deployment-diff.sh: the same script the poller runs, so the
report and the fleet cannot disagree about what a diff means. Render a table of
every target against the previous released SHA, note web_hot_swap on the server
row because it changes promotion from a restart to a bundle swap, and call out a
non-runtime-only range explicitly rather than showing five silent "no" rows.
Verified against real ranges rather than by reading. 21badd0..a5ff7e4 (the
upstream import, 37 runtime paths) reports every target selected;
3a7e7a4..a5ff7e4 (workflow files only) reports deploy=false and nothing
promoted.
The caveat is stated in the summary rather than left implicit: the poller diffs
against the last SHA it actually deployed, which is not always the last released
SHA, because a skipped or partly failed promotion leaves its baseline behind.
When they diverge the poller selects a superset of the reported rows, never a
subset, so the table cannot claim a target is moving when it is not.
Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
@patroza
patroza merged commit 885f127 into fork/devAug 6, 2026
5 checks passed
omegent-appBot 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>
Sign up for freeto 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

@patroza
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

ci(fork): report the full release scope, not just mobile - #349

Merged
patroza merged 1 commit into
fork/devfrom
fork-dev/release-summary-scope
Aug 6, 2026
Merged

ci(fork): report the full release scope, not just mobile#349
patroza merged 1 commit into
fork/devfrom
fork-dev/release-summary-scope

Conversation

@omegent-app

Copy link
Copy Markdown

The release summary asserted that server, Discord, desktop and VS Code are promoted by the poller,
but never said whether this SHA actually selects any of them. The one question worth asking — what
does this release move — still needed a trip to the smart host.

Change

Classify all seven keys instead of only mobile, using scripts/classify-deployment-diff.shthe
same script the poller runs
, so the report and the fleet cannot disagree about what a diff means.

The summary now renders, against the previous released SHA:

TargetSelectedPromoted by
Server (restart)yessmart-host poller
Discord botyessmart-host poller
Desktopyessmart-host poller
VS Codeyessmart-host poller
Mobile (EAS)yesthis workflow

Plus the diffed range, the classification basis, a collapsed changed-file list, and:

  • web_hot_swap shown on the server row, because it changes promotion from a restart to a bundle
    swap — a materially different operation to read as "server: yes".
  • A non-runtime-only range called out explicitly, rather than five silent no rows that look like a
    bug.

Verified against real ranges, not by reading

RangeResult
21badd04e..a5ff7e40c (upstream import, 37 runtime paths)deploy=true, every target selected
3a7e7a458..a5ff7e40c (workflow files only)deploy=false, nothing promoted

The caveat, stated in the summary itself

The poller diffs against the last SHA it actually deployed, which is not always the last
released SHA — a promotion it skipped, or one that failed part-way, leaves its baseline behind this
one. When they diverge the poller selects a superset of the reported rows, never a subset, so the
table cannot claim a target is moving when it is not. That direction is the safe one, and it is
written into the summary rather than left for someone to rediscover.

Making it exact would mean reading poller state that lives on the smart host and is not reachable
from CI, so the report is honest about being a faithful re-computation rather than a mirror.

Co-authored by @patroza

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

The release summary asserted that server, Discord, desktop and VS Code are
promoted by the poller but never said whether this SHA actually selects any of
them, so the one question worth asking — what does this release move — needed a
trip to the smart host to answer.
Classify all seven keys instead of only mobile, using
scripts/classify-deployment-diff.sh: the same script the poller runs, so the
report and the fleet cannot disagree about what a diff means. Render a table of
every target against the previous released SHA, note web_hot_swap on the server
row because it changes promotion from a restart to a bundle swap, and call out a
non-runtime-only range explicitly rather than showing five silent "no" rows.
Verified against real ranges rather than by reading. 21badd0..a5ff7e4 (the
upstream import, 37 runtime paths) reports every target selected;
3a7e7a4..a5ff7e4 (workflow files only) reports deploy=false and nothing
promoted.
The caveat is stated in the summary rather than left implicit: the poller diffs
against the last SHA it actually deployed, which is not always the last released
SHA, because a skipped or partly failed promotion leaves its baseline behind.
When they diverge the poller selects a superset of the reported rows, never a
subset, so the table cannot claim a target is moving when it is not.
Co-authored-by: Patrick Roza <42661+patroza@users.noreply.github.com>
@patroza
patroza merged commit 885f127 into fork/devAug 6, 2026
5 checks passed
omegent-appBot 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>
Sign up for freeto 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

@patroza