Skip to content

fix(fork-sync): the check battery runs every hyprws CI test job before a trunk push - #1499

Merged
donjor merged 1 commit into
hyprwsfrom
fix/fork-sync-test-parity
Oct 2, 2026
Merged

donjor merged 1 commit into
hyprwsfrom
fix/fork-sync-test-parity

Conversation

@donjor-agent

@donjor-agent donjor-agent Bot commented Oct 2, 2026

Copy link
Copy Markdown

🤖 claude/anthropic claude-opus-5-5 (high) · host
with worker claude/anthropic claude-opus-5-5 (high)

Problem

fork:sync pushes the trunk after its battery, and the battery ran no hyprws CI test job.
A red suite reached hyprws on three syncs (#1327).
On the 2026-10-02 sync a green dry-run battery hid a red server suite.

Change

Part Change
scripts/lib/fork-ci-jobs.ts new: reads every test* job from hyprws-ci.yml and expands matrix cells
runChecks runs checkCommands, then every derived job; red job stops at its first red step
Report CheckRow.job names the CI job; the error lists every red one
Env umask 022; scrubs T3_* and T3CODE_*
Sync workflow timeout-minutes 60 to 90
Docs fork-sync guide gets a Check battery section; skill names checks[].job

The driver does not hard-code the job list.
It throws on a step it cannot run as an exact vp argv.
It skips only sudo apt-get and git provisioning lines.
There is no skip flag, and a red row blocks the push.
Note: the battery also runs the scripts suite twice, once in fork:ci and once in Test Scripts.

Scope and approval

Closes #1327.
The decision comment there sets the scope: a pre-push battery and no candidate branch.

Close conditions

  • Unmoved: red sync leaves the trunk alone
  • Named: the report names the red suite
  • Guard: a test fails on an unrun CI job
  • No skip: no flag drops a job
  • Documented: the fork-sync guide states it

Verification

Condition Test
Unmoved, Named leaves the trunk alone and names the suite when one CI test job is red
Guard runs every hyprws CI test job before a direct trunk push
No skip takes no flag that drops a battery row
Env runs the battery with CI's umask and none of the live T3 instance's environment
Commands
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
vp run --filter @t3tools/scripts typecheck → exit 0
vp test run fork-sync.test.ts lib/fork-ci-jobs.test.ts fork-gate-headers.test.ts → exit 0 (56 passed)

Each derived job, umask 022, T3_* and T3CODE_* unset:
Test          → exit 0
Test Web      → exit 0
Test Scripts  → exit 0
Test Server 1 → exit 0
Test Server 2 → exit 0
Test Server 3 → exit 0

Claude Opus 5.5 in Claude Code.

Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no

…e a trunk push

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
@donjor
donjor merged commit 00b81ba into hyprws Oct 2, 2026
@donjor
donjor deleted the fix/fork-sync-test-parity branch October 2, 2026 03:57
donjor added a commit that referenced this pull request Oct 2, 2026
…e a trunk push (#1499)

## Problem

`fork:sync` pushes the trunk after its battery, and the battery ran no `hyprws CI` test job.
A red suite reached `hyprws` on three syncs (#1327).
On the 2026-10-02 sync a green dry-run battery hid a red server suite.

## Change

| Part | Change |
| --- | --- |
| `scripts/lib/fork-ci-jobs.ts` | new: reads every `test*` job from `hyprws-ci.yml` and expands matrix cells |
| `runChecks` | runs `checkCommands`, then every derived job; red job stops at its first red step |
| Report | `CheckRow.job` names the CI job; the error lists every red one |
| Env | umask `022`; scrubs `T3_*` and `T3CODE_*` |
| Sync workflow | `timeout-minutes` 60 to 90 |
| Docs | fork-sync guide gets a Check battery section; skill names `checks[].job` |

The driver does not hard-code the job list.
It throws on a step it cannot run as an exact `vp` argv.
It skips only `sudo apt-get` and `git` provisioning lines.
There is no skip flag, and a red row blocks the push.
Note: the battery also runs the scripts suite twice, once in `fork:ci` and once in Test Scripts.

## Scope and approval

Closes #1327.
The decision comment there sets the scope: a pre-push battery and no candidate branch.

## Close conditions

- [ ] **Unmoved:** red sync leaves the trunk alone
- [ ] **Named:** the report names the red suite
- [ ] **Guard:** a test fails on an unrun CI job
- [ ] **No skip:** no flag drops a job
- [ ] **Documented:** the fork-sync guide states it

## Verification

| Condition | Test |
| --- | --- |
| Unmoved, Named | `leaves the trunk alone and names the suite when one CI test job is red` |
| Guard | `runs every hyprws CI test job before a direct trunk push` |
| No skip | `takes no flag that drops a battery row` |
| Env | `runs the battery with CI's umask and none of the live T3 instance's environment` |

<details><summary>Commands</summary>

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
vp run --filter @t3tools/scripts typecheck → exit 0
vp test run fork-sync.test.ts lib/fork-ci-jobs.test.ts fork-gate-headers.test.ts → exit 0 (56 passed)

Each derived job, umask 022, T3_* and T3CODE_* unset:
Test          → exit 0
Test Web      → exit 0
Test Scripts  → exit 0
Test Server 1 → exit 0
Test Server 2 → exit 0
Test Server 3 → exit 0
```

</details>

Claude Opus 5.5 in Claude Code.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 2, 2026
…b before a trunk push (#1499)

The sync battery inherited GH_REPO and GH_HOST, which change the server's
GitHub repository resolution under test; scrub them like the rest.

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
donjor added a commit that referenced this pull request Oct 2, 2026
…layed blob (#1510)

## Problem

The hourly sync onto `v0.0.45` rebases clean, then Test Server 3 goes red on every run:

```text
FAIL src/sourceControl/GitHubCli.test.ts > GitHubCli.listPullRequestsByHead > reads heads on one repository in one GraphQL document
SchemaError: Expected a valid JSON string
```

The sync step exports `GH_REPO`, and the check battery inherits it.
Upstream's `resolveBaseRepository` (`apps/server/src/sourceControl/GitHubCli.ts:817`) returns `null` whenever `GH_REPO` is set, so the lookup falls back to `gh pr list` with no stdin, and the test's GraphQL mock fails to decode it.
Trunk has the same failure under `GH_REPO`; it only surfaced once #1499 put the server shards in the battery, and trunk reached its current base from a local sync with no `GH_REPO`.

## Change

Drop `GH_REPO` from the `Run the sync driver` env in `.github/workflows/hyprws-upstream-sync.yml`.
Every `gh` call in the driver already passes `--repo`, so the variable did nothing for it.
The comment now says why the variable must stay out.

## Scope and approval

Part of #1505. Only a clean sync run closes that issue.
`fixup!` of the commit that owns the line; the next fold dissolves it.

## Verification

| Tree | Env | Command | Result |
| --- | --- | --- | --- |
| Trunk rebased onto `v0.0.45` | `GH_REPO` set | `vp test run src/sourceControl/GitHubCli.test.ts` | exit 1, same `SchemaError` |
| Trunk rebased onto `v0.0.45` | none | same | exit 0, 24 passed |
| Trunk `646fa738cd4` | `GH_REPO` set | same | exit 1, same `SchemaError` |
| Trunk `646fa738cd4` | `GH_TOKEN` only | same | exit 0, 24 passed |

<details><summary>Shard and repo checks</summary>

Rebased copy, `vp run --filter t3 test --shard 3/3`:

```diff
- GH_TOKEN + GH_REPO (old step env): exit 1, 1 failed | 142 passed | 1 skipped (144)
+ GH_TOKEN only (new step env):      exit 0, 143 passed | 1 skipped (144)
```

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
```

</details>

Claude Opus 5.5, Claude Code.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 2, 2026
…b before a trunk push (#1499)

The sync battery inherited GH_REPO and GH_HOST, which change the server's
GitHub repository resolution under test; scrub them like the rest.

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
donjor added a commit that referenced this pull request Oct 2, 2026
…1510)

## Problem

The hourly sync onto `v0.0.45` rebases clean, then Test Server 3 goes red on every run:

```text
FAIL src/sourceControl/GitHubCli.test.ts > GitHubCli.listPullRequestsByHead > reads heads on one repository in one GraphQL document
SchemaError: Expected a valid JSON string
```

The sync step exports `GH_REPO`, and the check battery inherits it.
Upstream's `resolveBaseRepository` (`apps/server/src/sourceControl/GitHubCli.ts:817`) returns `null` whenever `GH_REPO` is set, so the lookup falls back to `gh pr list` with no stdin, and the test's GraphQL mock fails to decode it.
Trunk has the same failure under `GH_REPO`; it only surfaced once #1499 put the server shards in the battery, and trunk reached its current base from a local sync with no `GH_REPO`.

## Change

Drop `GH_REPO` from the `Run the sync driver` env in `.github/workflows/hyprws-upstream-sync.yml`.
Every `gh` call in the driver already passes `--repo`, so the variable did nothing for it.
The comment now says why the variable must stay out.

## Scope and approval

Part of #1505. Only a clean sync run closes that issue.
Landed as a `fixup!` of 06a999c, which could not fold there: #1504 rewrote the same lines later. Reworded in place to a standalone commit.

## Verification

| Tree | Env | Command | Result |
| --- | --- | --- | --- |
| Trunk rebased onto `v0.0.45` | `GH_REPO` set | `vp test run src/sourceControl/GitHubCli.test.ts` | exit 1, same `SchemaError` |
| Trunk rebased onto `v0.0.45` | none | same | exit 0, 24 passed |
| Trunk `646fa738cd4` | `GH_REPO` set | same | exit 1, same `SchemaError` |
| Trunk `646fa738cd4` | `GH_TOKEN` only | same | exit 0, 24 passed |

<details><summary>Shard and repo checks</summary>

Rebased copy, `vp run --filter t3 test --shard 3/3`:

```diff
- GH_TOKEN + GH_REPO (old step env): exit 1, 1 failed | 142 passed | 1 skipped (144)
+ GH_TOKEN only (new step env):      exit 0, 143 passed | 1 skipped (144)
```

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
```

</details>

Claude Opus 5.5, Claude Code.

Squashes:
- ea1a440 fixup! fix(fork-sync): read hook markers at the fork tip, not the replayed blob (#1510)

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 2, 2026
…b before a trunk push (#1499)

The sync battery inherited GH_REPO and GH_HOST, which change the server's
GitHub repository resolution under test; scrub them like the rest.

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
donjor added a commit that referenced this pull request Oct 2, 2026
…b before a trunk push (#1499) (#1512)

## Problem

A sync run from a shell that exports `GH_REPO` or `GH_HOST` goes red, because the server's GitHub code under test (`resolveBaseRepository`) changes behaviour when they are set.

## Change

Add `GH_REPO` and `GH_HOST` to the battery's scrubbed environment keys; `GH_TOKEN` stays.
The existing env-scrub test now covers both.
Folds into the `#1499` battery commit, which owns the scrub and its test.

## Scope and approval

Part of #1505.
Two keys in an existing set; the CI-side cause is #1510.

## Verification

- **Test:** `vp test run scripts/fork-sync.test.ts` → exit 0
- **Red without fix:** the extended case fails
- **CI:** `vp run fork:ci` → exit 0
- **Fold:** `rebase -i --autosquash` made no stops, empty diff

Claude Code (claude-sonnet-5-5)

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 3, 2026
…e a trunk push (#1499)

## Problem

`fork:sync` pushes the trunk after its battery, and the battery ran no `hyprws CI` test job.
A red suite reached `hyprws` on three syncs (#1327).
On the 2026-10-02 sync a green dry-run battery hid a red server suite.

## Change

| Part | Change |
| --- | --- |
| `scripts/lib/fork-ci-jobs.ts` | new: reads every `test*` job from `hyprws-ci.yml` and expands matrix cells |
| `runChecks` | runs `checkCommands`, then every derived job; red job stops at its first red step |
| Report | `CheckRow.job` names the CI job; the error lists every red one |
| Env | umask `022`; scrubs `T3_*` and `T3CODE_*` |
| Sync workflow | `timeout-minutes` 60 to 90 |
| Docs | fork-sync guide gets a Check battery section; skill names `checks[].job` |

The driver does not hard-code the job list.
It throws on a step it cannot run as an exact `vp` argv.
It skips only `sudo apt-get` and `git` provisioning lines.
There is no skip flag, and a red row blocks the push.
Note: the battery also runs the scripts suite twice, once in `fork:ci` and once in Test Scripts.

## Scope and approval

Closes #1327.
The decision comment there sets the scope: a pre-push battery and no candidate branch.

## Close conditions

- [ ] **Unmoved:** red sync leaves the trunk alone
- [ ] **Named:** the report names the red suite
- [ ] **Guard:** a test fails on an unrun CI job
- [ ] **No skip:** no flag drops a job
- [ ] **Documented:** the fork-sync guide states it

## Verification

| Condition | Test |
| --- | --- |
| Unmoved, Named | `leaves the trunk alone and names the suite when one CI test job is red` |
| Guard | `runs every hyprws CI test job before a direct trunk push` |
| No skip | `takes no flag that drops a battery row` |
| Env | `runs the battery with CI's umask and none of the live T3 instance's environment` |

<details><summary>Commands</summary>

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
vp run --filter @t3tools/scripts typecheck → exit 0
vp test run fork-sync.test.ts lib/fork-ci-jobs.test.ts fork-gate-headers.test.ts → exit 0 (56 passed)

Each derived job, umask 022, T3_* and T3CODE_* unset:
Test          → exit 0
Test Web      → exit 0
Test Scripts  → exit 0
Test Server 1 → exit 0
Test Server 2 → exit 0
Test Server 3 → exit 0
```

</details>

Claude Opus 5.5 in Claude Code.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 3, 2026
…1510)

## Problem

The hourly sync onto `v0.0.45` rebases clean, then Test Server 3 goes red on every run:

```text
FAIL src/sourceControl/GitHubCli.test.ts > GitHubCli.listPullRequestsByHead > reads heads on one repository in one GraphQL document
SchemaError: Expected a valid JSON string
```

The sync step exports `GH_REPO`, and the check battery inherits it.
Upstream's `resolveBaseRepository` (`apps/server/src/sourceControl/GitHubCli.ts:817`) returns `null` whenever `GH_REPO` is set, so the lookup falls back to `gh pr list` with no stdin, and the test's GraphQL mock fails to decode it.
Trunk has the same failure under `GH_REPO`; it only surfaced once #1499 put the server shards in the battery, and trunk reached its current base from a local sync with no `GH_REPO`.

## Change

Drop `GH_REPO` from the `Run the sync driver` env in `.github/workflows/hyprws-upstream-sync.yml`.
Every `gh` call in the driver already passes `--repo`, so the variable did nothing for it.
The comment now says why the variable must stay out.

## Scope and approval

Part of #1505. Only a clean sync run closes that issue.
Landed as a `fixup!` of 06a999c, which could not fold there: #1504 rewrote the same lines later. Reworded in place to a standalone commit.

## Verification

| Tree | Env | Command | Result |
| --- | --- | --- | --- |
| Trunk rebased onto `v0.0.45` | `GH_REPO` set | `vp test run src/sourceControl/GitHubCli.test.ts` | exit 1, same `SchemaError` |
| Trunk rebased onto `v0.0.45` | none | same | exit 0, 24 passed |
| Trunk `646fa738cd4` | `GH_REPO` set | same | exit 1, same `SchemaError` |
| Trunk `646fa738cd4` | `GH_TOKEN` only | same | exit 0, 24 passed |

<details><summary>Shard and repo checks</summary>

Rebased copy, `vp run --filter t3 test --shard 3/3`:

```diff
- GH_TOKEN + GH_REPO (old step env): exit 1, 1 failed | 142 passed | 1 skipped (144)
+ GH_TOKEN only (new step env):      exit 0, 143 passed | 1 skipped (144)
```

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
```

</details>

Claude Opus 5.5, Claude Code.

Squashes:
- ea1a440 fixup! fix(fork-sync): read hook markers at the fork tip, not the replayed blob (#1510)

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor pushed a commit that referenced this pull request Oct 3, 2026
…e a trunk push (#1499)

## Problem

`fork:sync` pushes the trunk after its battery, and the battery ran no `hyprws CI` test job.
A red suite reached `hyprws` on three syncs (#1327).
On the 2026-10-02 sync a green dry-run battery hid a red server suite.

## Change

| Part | Change |
| --- | --- |
| `scripts/lib/fork-ci-jobs.ts` | new: reads every `test*` job from `hyprws-ci.yml` and expands matrix cells |
| `runChecks` | runs `checkCommands`, then every derived job; red job stops at its first red step |
| Report | `CheckRow.job` names the CI job; the error lists every red one |
| Env | umask `022`; scrubs `T3_*` and `T3CODE_*` |
| Sync workflow | `timeout-minutes` 60 to 90 |
| Docs | fork-sync guide gets a Check battery section; skill names `checks[].job` |

The driver does not hard-code the job list.
It throws on a step it cannot run as an exact `vp` argv.
It skips only `sudo apt-get` and `git` provisioning lines.
There is no skip flag, and a red row blocks the push.
Note: the battery also runs the scripts suite twice, once in `fork:ci` and once in Test Scripts.

## Scope and approval

Closes #1327.
The decision comment there sets the scope: a pre-push battery and no candidate branch.

## Close conditions

- [ ] **Unmoved:** red sync leaves the trunk alone
- [ ] **Named:** the report names the red suite
- [ ] **Guard:** a test fails on an unrun CI job
- [ ] **No skip:** no flag drops a job
- [ ] **Documented:** the fork-sync guide states it

## Verification

| Condition | Test |
| --- | --- |
| Unmoved, Named | `leaves the trunk alone and names the suite when one CI test job is red` |
| Guard | `runs every hyprws CI test job before a direct trunk push` |
| No skip | `takes no flag that drops a battery row` |
| Env | `runs the battery with CI's umask and none of the live T3 instance's environment` |

<details><summary>Commands</summary>

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
vp run --filter @t3tools/scripts typecheck → exit 0
vp test run fork-sync.test.ts lib/fork-ci-jobs.test.ts fork-gate-headers.test.ts → exit 0 (56 passed)

Each derived job, umask 022, T3_* and T3CODE_* unset:
Test          → exit 0
Test Web      → exit 0
Test Scripts  → exit 0
Test Server 1 → exit 0
Test Server 2 → exit 0
Test Server 3 → exit 0
```

</details>

Claude Opus 5.5 in Claude Code.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor pushed a commit that referenced this pull request Oct 3, 2026
…1510)

## Problem

The hourly sync onto `v0.0.45` rebases clean, then Test Server 3 goes red on every run:

```text
FAIL src/sourceControl/GitHubCli.test.ts > GitHubCli.listPullRequestsByHead > reads heads on one repository in one GraphQL document
SchemaError: Expected a valid JSON string
```

The sync step exports `GH_REPO`, and the check battery inherits it.
Upstream's `resolveBaseRepository` (`apps/server/src/sourceControl/GitHubCli.ts:817`) returns `null` whenever `GH_REPO` is set, so the lookup falls back to `gh pr list` with no stdin, and the test's GraphQL mock fails to decode it.
Trunk has the same failure under `GH_REPO`; it only surfaced once #1499 put the server shards in the battery, and trunk reached its current base from a local sync with no `GH_REPO`.

## Change

Drop `GH_REPO` from the `Run the sync driver` env in `.github/workflows/hyprws-upstream-sync.yml`.
Every `gh` call in the driver already passes `--repo`, so the variable did nothing for it.
The comment now says why the variable must stay out.

## Scope and approval

Part of #1505. Only a clean sync run closes that issue.
Landed as a `fixup!` of 06a999c, which could not fold there: #1504 rewrote the same lines later. Reworded in place to a standalone commit.

## Verification

| Tree | Env | Command | Result |
| --- | --- | --- | --- |
| Trunk rebased onto `v0.0.45` | `GH_REPO` set | `vp test run src/sourceControl/GitHubCli.test.ts` | exit 1, same `SchemaError` |
| Trunk rebased onto `v0.0.45` | none | same | exit 0, 24 passed |
| Trunk `646fa738cd4` | `GH_REPO` set | same | exit 1, same `SchemaError` |
| Trunk `646fa738cd4` | `GH_TOKEN` only | same | exit 0, 24 passed |

<details><summary>Shard and repo checks</summary>

Rebased copy, `vp run --filter t3 test --shard 3/3`:

```diff
- GH_TOKEN + GH_REPO (old step env): exit 1, 1 failed | 142 passed | 1 skipped (144)
+ GH_TOKEN only (new step env):      exit 0, 143 passed | 1 skipped (144)
```

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
```

</details>

Claude Opus 5.5, Claude Code.

Squashes:
- ea1a440 fixup! fix(fork-sync): read hook markers at the fork tip, not the replayed blob (#1510)

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor pushed a commit that referenced this pull request Oct 3, 2026
…e a trunk push (#1499)

## Problem

`fork:sync` pushes the trunk after its battery, and the battery ran no `hyprws CI` test job.
A red suite reached `hyprws` on three syncs (#1327).
On the 2026-10-02 sync a green dry-run battery hid a red server suite.

## Change

| Part | Change |
| --- | --- |
| `scripts/lib/fork-ci-jobs.ts` | new: reads every `test*` job from `hyprws-ci.yml` and expands matrix cells |
| `runChecks` | runs `checkCommands`, then every derived job; red job stops at its first red step |
| Report | `CheckRow.job` names the CI job; the error lists every red one |
| Env | umask `022`; scrubs `T3_*` and `T3CODE_*` |
| Sync workflow | `timeout-minutes` 60 to 90 |
| Docs | fork-sync guide gets a Check battery section; skill names `checks[].job` |

The driver does not hard-code the job list.
It throws on a step it cannot run as an exact `vp` argv.
It skips only `sudo apt-get` and `git` provisioning lines.
There is no skip flag, and a red row blocks the push.
Note: the battery also runs the scripts suite twice, once in `fork:ci` and once in Test Scripts.

## Scope and approval

Closes #1327.
The decision comment there sets the scope: a pre-push battery and no candidate branch.

## Close conditions

- [ ] **Unmoved:** red sync leaves the trunk alone
- [ ] **Named:** the report names the red suite
- [ ] **Guard:** a test fails on an unrun CI job
- [ ] **No skip:** no flag drops a job
- [ ] **Documented:** the fork-sync guide states it

## Verification

| Condition | Test |
| --- | --- |
| Unmoved, Named | `leaves the trunk alone and names the suite when one CI test job is red` |
| Guard | `runs every hyprws CI test job before a direct trunk push` |
| No skip | `takes no flag that drops a battery row` |
| Env | `runs the battery with CI's umask and none of the live T3 instance's environment` |

<details><summary>Commands</summary>

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
vp run --filter @t3tools/scripts typecheck → exit 0
vp test run fork-sync.test.ts lib/fork-ci-jobs.test.ts fork-gate-headers.test.ts → exit 0 (56 passed)

Each derived job, umask 022, T3_* and T3CODE_* unset:
Test          → exit 0
Test Web      → exit 0
Test Scripts  → exit 0
Test Server 1 → exit 0
Test Server 2 → exit 0
Test Server 3 → exit 0
```

</details>

Claude Opus 5.5 in Claude Code.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor pushed a commit that referenced this pull request Oct 3, 2026
…1510)

## Problem

The hourly sync onto `v0.0.45` rebases clean, then Test Server 3 goes red on every run:

```text
FAIL src/sourceControl/GitHubCli.test.ts > GitHubCli.listPullRequestsByHead > reads heads on one repository in one GraphQL document
SchemaError: Expected a valid JSON string
```

The sync step exports `GH_REPO`, and the check battery inherits it.
Upstream's `resolveBaseRepository` (`apps/server/src/sourceControl/GitHubCli.ts:817`) returns `null` whenever `GH_REPO` is set, so the lookup falls back to `gh pr list` with no stdin, and the test's GraphQL mock fails to decode it.
Trunk has the same failure under `GH_REPO`; it only surfaced once #1499 put the server shards in the battery, and trunk reached its current base from a local sync with no `GH_REPO`.

## Change

Drop `GH_REPO` from the `Run the sync driver` env in `.github/workflows/hyprws-upstream-sync.yml`.
Every `gh` call in the driver already passes `--repo`, so the variable did nothing for it.
The comment now says why the variable must stay out.

## Scope and approval

Part of #1505. Only a clean sync run closes that issue.
Landed as a `fixup!` of 06a999c, which could not fold there: #1504 rewrote the same lines later. Reworded in place to a standalone commit.

## Verification

| Tree | Env | Command | Result |
| --- | --- | --- | --- |
| Trunk rebased onto `v0.0.45` | `GH_REPO` set | `vp test run src/sourceControl/GitHubCli.test.ts` | exit 1, same `SchemaError` |
| Trunk rebased onto `v0.0.45` | none | same | exit 0, 24 passed |
| Trunk `646fa738cd4` | `GH_REPO` set | same | exit 1, same `SchemaError` |
| Trunk `646fa738cd4` | `GH_TOKEN` only | same | exit 0, 24 passed |

<details><summary>Shard and repo checks</summary>

Rebased copy, `vp run --filter t3 test --shard 3/3`:

```diff
- GH_TOKEN + GH_REPO (old step env): exit 1, 1 failed | 142 passed | 1 skipped (144)
+ GH_TOKEN only (new step env):      exit 0, 143 passed | 1 skipped (144)
```

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
```

</details>

Claude Opus 5.5, Claude Code.

Squashes:
- ea1a440 fixup! fix(fork-sync): read hook markers at the fork tip, not the replayed blob (#1510)

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor pushed a commit that referenced this pull request Oct 4, 2026
…e a trunk push (#1499)

## Problem

`fork:sync` pushes the trunk after its battery, and the battery ran no `hyprws CI` test job.
A red suite reached `hyprws` on three syncs (#1327).
On the 2026-10-02 sync a green dry-run battery hid a red server suite.

## Change

| Part | Change |
| --- | --- |
| `scripts/lib/fork-ci-jobs.ts` | new: reads every `test*` job from `hyprws-ci.yml` and expands matrix cells |
| `runChecks` | runs `checkCommands`, then every derived job; red job stops at its first red step |
| Report | `CheckRow.job` names the CI job; the error lists every red one |
| Env | umask `022`; scrubs `T3_*` and `T3CODE_*` |
| Sync workflow | `timeout-minutes` 60 to 90 |
| Docs | fork-sync guide gets a Check battery section; skill names `checks[].job` |

The driver does not hard-code the job list.
It throws on a step it cannot run as an exact `vp` argv.
It skips only `sudo apt-get` and `git` provisioning lines.
There is no skip flag, and a red row blocks the push.
Note: the battery also runs the scripts suite twice, once in `fork:ci` and once in Test Scripts.

## Scope and approval

Closes #1327.
The decision comment there sets the scope: a pre-push battery and no candidate branch.

## Close conditions

- [ ] **Unmoved:** red sync leaves the trunk alone
- [ ] **Named:** the report names the red suite
- [ ] **Guard:** a test fails on an unrun CI job
- [ ] **No skip:** no flag drops a job
- [ ] **Documented:** the fork-sync guide states it

## Verification

| Condition | Test |
| --- | --- |
| Unmoved, Named | `leaves the trunk alone and names the suite when one CI test job is red` |
| Guard | `runs every hyprws CI test job before a direct trunk push` |
| No skip | `takes no flag that drops a battery row` |
| Env | `runs the battery with CI's umask and none of the live T3 instance's environment` |

<details><summary>Commands</summary>

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
vp run --filter @t3tools/scripts typecheck → exit 0
vp test run fork-sync.test.ts lib/fork-ci-jobs.test.ts fork-gate-headers.test.ts → exit 0 (56 passed)

Each derived job, umask 022, T3_* and T3CODE_* unset:
Test          → exit 0
Test Web      → exit 0
Test Scripts  → exit 0
Test Server 1 → exit 0
Test Server 2 → exit 0
Test Server 3 → exit 0
```

</details>

Claude Opus 5.5 in Claude Code.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor pushed a commit that referenced this pull request Oct 4, 2026
…1510)

## Problem

The hourly sync onto `v0.0.45` rebases clean, then Test Server 3 goes red on every run:

```text
FAIL src/sourceControl/GitHubCli.test.ts > GitHubCli.listPullRequestsByHead > reads heads on one repository in one GraphQL document
SchemaError: Expected a valid JSON string
```

The sync step exports `GH_REPO`, and the check battery inherits it.
Upstream's `resolveBaseRepository` (`apps/server/src/sourceControl/GitHubCli.ts:817`) returns `null` whenever `GH_REPO` is set, so the lookup falls back to `gh pr list` with no stdin, and the test's GraphQL mock fails to decode it.
Trunk has the same failure under `GH_REPO`; it only surfaced once #1499 put the server shards in the battery, and trunk reached its current base from a local sync with no `GH_REPO`.

## Change

Drop `GH_REPO` from the `Run the sync driver` env in `.github/workflows/hyprws-upstream-sync.yml`.
Every `gh` call in the driver already passes `--repo`, so the variable did nothing for it.
The comment now says why the variable must stay out.

## Scope and approval

Part of #1505. Only a clean sync run closes that issue.
Landed as a `fixup!` of 06a999c, which could not fold there: #1504 rewrote the same lines later. Reworded in place to a standalone commit.

## Verification

| Tree | Env | Command | Result |
| --- | --- | --- | --- |
| Trunk rebased onto `v0.0.45` | `GH_REPO` set | `vp test run src/sourceControl/GitHubCli.test.ts` | exit 1, same `SchemaError` |
| Trunk rebased onto `v0.0.45` | none | same | exit 0, 24 passed |
| Trunk `646fa738cd4` | `GH_REPO` set | same | exit 1, same `SchemaError` |
| Trunk `646fa738cd4` | `GH_TOKEN` only | same | exit 0, 24 passed |

<details><summary>Shard and repo checks</summary>

Rebased copy, `vp run --filter t3 test --shard 3/3`:

```diff
- GH_TOKEN + GH_REPO (old step env): exit 1, 1 failed | 142 passed | 1 skipped (144)
+ GH_TOKEN only (new step env):      exit 0, 143 passed | 1 skipped (144)
```

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
```

</details>

Claude Opus 5.5, Claude Code.

Squashes:
- ea1a440 fixup! fix(fork-sync): read hook markers at the fork tip, not the replayed blob (#1510)

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor pushed a commit that referenced this pull request Oct 4, 2026
…e a trunk push (#1499)

## Problem

`fork:sync` pushes the trunk after its battery, and the battery ran no `hyprws CI` test job.
A red suite reached `hyprws` on three syncs (#1327).
On the 2026-10-02 sync a green dry-run battery hid a red server suite.

## Change

| Part | Change |
| --- | --- |
| `scripts/lib/fork-ci-jobs.ts` | new: reads every `test*` job from `hyprws-ci.yml` and expands matrix cells |
| `runChecks` | runs `checkCommands`, then every derived job; red job stops at its first red step |
| Report | `CheckRow.job` names the CI job; the error lists every red one |
| Env | umask `022`; scrubs `T3_*` and `T3CODE_*` |
| Sync workflow | `timeout-minutes` 60 to 90 |
| Docs | fork-sync guide gets a Check battery section; skill names `checks[].job` |

The driver does not hard-code the job list.
It throws on a step it cannot run as an exact `vp` argv.
It skips only `sudo apt-get` and `git` provisioning lines.
There is no skip flag, and a red row blocks the push.
Note: the battery also runs the scripts suite twice, once in `fork:ci` and once in Test Scripts.

## Scope and approval

Closes #1327.
The decision comment there sets the scope: a pre-push battery and no candidate branch.

## Close conditions

- [ ] **Unmoved:** red sync leaves the trunk alone
- [ ] **Named:** the report names the red suite
- [ ] **Guard:** a test fails on an unrun CI job
- [ ] **No skip:** no flag drops a job
- [ ] **Documented:** the fork-sync guide states it

## Verification

| Condition | Test |
| --- | --- |
| Unmoved, Named | `leaves the trunk alone and names the suite when one CI test job is red` |
| Guard | `runs every hyprws CI test job before a direct trunk push` |
| No skip | `takes no flag that drops a battery row` |
| Env | `runs the battery with CI's umask and none of the live T3 instance's environment` |

<details><summary>Commands</summary>

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
vp run --filter @t3tools/scripts typecheck → exit 0
vp test run fork-sync.test.ts lib/fork-ci-jobs.test.ts fork-gate-headers.test.ts → exit 0 (56 passed)

Each derived job, umask 022, T3_* and T3CODE_* unset:
Test          → exit 0
Test Web      → exit 0
Test Scripts  → exit 0
Test Server 1 → exit 0
Test Server 2 → exit 0
Test Server 3 → exit 0
```

</details>

Claude Opus 5.5 in Claude Code.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor pushed a commit that referenced this pull request Oct 4, 2026
…1510)

## Problem

The hourly sync onto `v0.0.45` rebases clean, then Test Server 3 goes red on every run:

```text
FAIL src/sourceControl/GitHubCli.test.ts > GitHubCli.listPullRequestsByHead > reads heads on one repository in one GraphQL document
SchemaError: Expected a valid JSON string
```

The sync step exports `GH_REPO`, and the check battery inherits it.
Upstream's `resolveBaseRepository` (`apps/server/src/sourceControl/GitHubCli.ts:817`) returns `null` whenever `GH_REPO` is set, so the lookup falls back to `gh pr list` with no stdin, and the test's GraphQL mock fails to decode it.
Trunk has the same failure under `GH_REPO`; it only surfaced once #1499 put the server shards in the battery, and trunk reached its current base from a local sync with no `GH_REPO`.

## Change

Drop `GH_REPO` from the `Run the sync driver` env in `.github/workflows/hyprws-upstream-sync.yml`.
Every `gh` call in the driver already passes `--repo`, so the variable did nothing for it.
The comment now says why the variable must stay out.

## Scope and approval

Part of #1505. Only a clean sync run closes that issue.
Landed as a `fixup!` of 06a999c, which could not fold there: #1504 rewrote the same lines later. Reworded in place to a standalone commit.

## Verification

| Tree | Env | Command | Result |
| --- | --- | --- | --- |
| Trunk rebased onto `v0.0.45` | `GH_REPO` set | `vp test run src/sourceControl/GitHubCli.test.ts` | exit 1, same `SchemaError` |
| Trunk rebased onto `v0.0.45` | none | same | exit 0, 24 passed |
| Trunk `646fa738cd4` | `GH_REPO` set | same | exit 1, same `SchemaError` |
| Trunk `646fa738cd4` | `GH_TOKEN` only | same | exit 0, 24 passed |

<details><summary>Shard and repo checks</summary>

Rebased copy, `vp run --filter t3 test --shard 3/3`:

```diff
- GH_TOKEN + GH_REPO (old step env): exit 1, 1 failed | 142 passed | 1 skipped (144)
+ GH_TOKEN only (new step env):      exit 0, 143 passed | 1 skipped (144)
```

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
```

</details>

Claude Opus 5.5, Claude Code.

Squashes:
- ea1a440 fixup! fix(fork-sync): read hook markers at the fork tip, not the replayed blob (#1510)

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor pushed a commit that referenced this pull request Oct 4, 2026
…e a trunk push (#1499)

## Problem

`fork:sync` pushes the trunk after its battery, and the battery ran no `hyprws CI` test job.
A red suite reached `hyprws` on three syncs (#1327).
On the 2026-10-02 sync a green dry-run battery hid a red server suite.

## Change

| Part | Change |
| --- | --- |
| `scripts/lib/fork-ci-jobs.ts` | new: reads every `test*` job from `hyprws-ci.yml` and expands matrix cells |
| `runChecks` | runs `checkCommands`, then every derived job; red job stops at its first red step |
| Report | `CheckRow.job` names the CI job; the error lists every red one |
| Env | umask `022`; scrubs `T3_*` and `T3CODE_*` |
| Sync workflow | `timeout-minutes` 60 to 90 |
| Docs | fork-sync guide gets a Check battery section; skill names `checks[].job` |

The driver does not hard-code the job list.
It throws on a step it cannot run as an exact `vp` argv.
It skips only `sudo apt-get` and `git` provisioning lines.
There is no skip flag, and a red row blocks the push.
Note: the battery also runs the scripts suite twice, once in `fork:ci` and once in Test Scripts.

## Scope and approval

Closes #1327.
The decision comment there sets the scope: a pre-push battery and no candidate branch.

## Close conditions

- [ ] **Unmoved:** red sync leaves the trunk alone
- [ ] **Named:** the report names the red suite
- [ ] **Guard:** a test fails on an unrun CI job
- [ ] **No skip:** no flag drops a job
- [ ] **Documented:** the fork-sync guide states it

## Verification

| Condition | Test |
| --- | --- |
| Unmoved, Named | `leaves the trunk alone and names the suite when one CI test job is red` |
| Guard | `runs every hyprws CI test job before a direct trunk push` |
| No skip | `takes no flag that drops a battery row` |
| Env | `runs the battery with CI's umask and none of the live T3 instance's environment` |

<details><summary>Commands</summary>

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
vp run --filter @t3tools/scripts typecheck → exit 0
vp test run fork-sync.test.ts lib/fork-ci-jobs.test.ts fork-gate-headers.test.ts → exit 0 (56 passed)

Each derived job, umask 022, T3_* and T3CODE_* unset:
Test          → exit 0
Test Web      → exit 0
Test Scripts  → exit 0
Test Server 1 → exit 0
Test Server 2 → exit 0
Test Server 3 → exit 0
```

</details>

Claude Opus 5.5 in Claude Code.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor pushed a commit that referenced this pull request Oct 4, 2026
…1510)

## Problem

The hourly sync onto `v0.0.45` rebases clean, then Test Server 3 goes red on every run:

```text
FAIL src/sourceControl/GitHubCli.test.ts > GitHubCli.listPullRequestsByHead > reads heads on one repository in one GraphQL document
SchemaError: Expected a valid JSON string
```

The sync step exports `GH_REPO`, and the check battery inherits it.
Upstream's `resolveBaseRepository` (`apps/server/src/sourceControl/GitHubCli.ts:817`) returns `null` whenever `GH_REPO` is set, so the lookup falls back to `gh pr list` with no stdin, and the test's GraphQL mock fails to decode it.
Trunk has the same failure under `GH_REPO`; it only surfaced once #1499 put the server shards in the battery, and trunk reached its current base from a local sync with no `GH_REPO`.

## Change

Drop `GH_REPO` from the `Run the sync driver` env in `.github/workflows/hyprws-upstream-sync.yml`.
Every `gh` call in the driver already passes `--repo`, so the variable did nothing for it.
The comment now says why the variable must stay out.

## Scope and approval

Part of #1505. Only a clean sync run closes that issue.
Landed as a `fixup!` of 06a999c, which could not fold there: #1504 rewrote the same lines later. Reworded in place to a standalone commit.

## Verification

| Tree | Env | Command | Result |
| --- | --- | --- | --- |
| Trunk rebased onto `v0.0.45` | `GH_REPO` set | `vp test run src/sourceControl/GitHubCli.test.ts` | exit 1, same `SchemaError` |
| Trunk rebased onto `v0.0.45` | none | same | exit 0, 24 passed |
| Trunk `646fa738cd4` | `GH_REPO` set | same | exit 1, same `SchemaError` |
| Trunk `646fa738cd4` | `GH_TOKEN` only | same | exit 0, 24 passed |

<details><summary>Shard and repo checks</summary>

Rebased copy, `vp run --filter t3 test --shard 3/3`:

```diff
- GH_TOKEN + GH_REPO (old step env): exit 1, 1 failed | 142 passed | 1 skipped (144)
+ GH_TOKEN only (new step env):      exit 0, 143 passed | 1 skipped (144)
```

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
```

</details>

Claude Opus 5.5, Claude Code.

Squashes:
- ea1a440 fixup! fix(fork-sync): read hook markers at the fork tip, not the replayed blob (#1510)

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor pushed a commit that referenced this pull request Oct 4, 2026
…e a trunk push (#1499)

## Problem

`fork:sync` pushes the trunk after its battery, and the battery ran no `hyprws CI` test job.
A red suite reached `hyprws` on three syncs (#1327).
On the 2026-10-02 sync a green dry-run battery hid a red server suite.

## Change

| Part | Change |
| --- | --- |
| `scripts/lib/fork-ci-jobs.ts` | new: reads every `test*` job from `hyprws-ci.yml` and expands matrix cells |
| `runChecks` | runs `checkCommands`, then every derived job; red job stops at its first red step |
| Report | `CheckRow.job` names the CI job; the error lists every red one |
| Env | umask `022`; scrubs `T3_*` and `T3CODE_*` |
| Sync workflow | `timeout-minutes` 60 to 90 |
| Docs | fork-sync guide gets a Check battery section; skill names `checks[].job` |

The driver does not hard-code the job list.
It throws on a step it cannot run as an exact `vp` argv.
It skips only `sudo apt-get` and `git` provisioning lines.
There is no skip flag, and a red row blocks the push.
Note: the battery also runs the scripts suite twice, once in `fork:ci` and once in Test Scripts.

## Scope and approval

Closes #1327.
The decision comment there sets the scope: a pre-push battery and no candidate branch.

## Close conditions

- [ ] **Unmoved:** red sync leaves the trunk alone
- [ ] **Named:** the report names the red suite
- [ ] **Guard:** a test fails on an unrun CI job
- [ ] **No skip:** no flag drops a job
- [ ] **Documented:** the fork-sync guide states it

## Verification

| Condition | Test |
| --- | --- |
| Unmoved, Named | `leaves the trunk alone and names the suite when one CI test job is red` |
| Guard | `runs every hyprws CI test job before a direct trunk push` |
| No skip | `takes no flag that drops a battery row` |
| Env | `runs the battery with CI's umask and none of the live T3 instance's environment` |

<details><summary>Commands</summary>

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
vp run --filter @t3tools/scripts typecheck → exit 0
vp test run fork-sync.test.ts lib/fork-ci-jobs.test.ts fork-gate-headers.test.ts → exit 0 (56 passed)

Each derived job, umask 022, T3_* and T3CODE_* unset:
Test          → exit 0
Test Web      → exit 0
Test Scripts  → exit 0
Test Server 1 → exit 0
Test Server 2 → exit 0
Test Server 3 → exit 0
```

</details>

Claude Opus 5.5 in Claude Code.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor pushed a commit that referenced this pull request Oct 4, 2026
…1510)

## Problem

The hourly sync onto `v0.0.45` rebases clean, then Test Server 3 goes red on every run:

```text
FAIL src/sourceControl/GitHubCli.test.ts > GitHubCli.listPullRequestsByHead > reads heads on one repository in one GraphQL document
SchemaError: Expected a valid JSON string
```

The sync step exports `GH_REPO`, and the check battery inherits it.
Upstream's `resolveBaseRepository` (`apps/server/src/sourceControl/GitHubCli.ts:817`) returns `null` whenever `GH_REPO` is set, so the lookup falls back to `gh pr list` with no stdin, and the test's GraphQL mock fails to decode it.
Trunk has the same failure under `GH_REPO`; it only surfaced once #1499 put the server shards in the battery, and trunk reached its current base from a local sync with no `GH_REPO`.

## Change

Drop `GH_REPO` from the `Run the sync driver` env in `.github/workflows/hyprws-upstream-sync.yml`.
Every `gh` call in the driver already passes `--repo`, so the variable did nothing for it.
The comment now says why the variable must stay out.

## Scope and approval

Part of #1505. Only a clean sync run closes that issue.
Landed as a `fixup!` of 06a999c, which could not fold there: #1504 rewrote the same lines later. Reworded in place to a standalone commit.

## Verification

| Tree | Env | Command | Result |
| --- | --- | --- | --- |
| Trunk rebased onto `v0.0.45` | `GH_REPO` set | `vp test run src/sourceControl/GitHubCli.test.ts` | exit 1, same `SchemaError` |
| Trunk rebased onto `v0.0.45` | none | same | exit 0, 24 passed |
| Trunk `646fa738cd4` | `GH_REPO` set | same | exit 1, same `SchemaError` |
| Trunk `646fa738cd4` | `GH_TOKEN` only | same | exit 0, 24 passed |

<details><summary>Shard and repo checks</summary>

Rebased copy, `vp run --filter t3 test --shard 3/3`:

```diff
- GH_TOKEN + GH_REPO (old step env): exit 1, 1 failed | 142 passed | 1 skipped (144)
+ GH_TOKEN only (new step env):      exit 0, 143 passed | 1 skipped (144)
```

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
```

</details>

Claude Opus 5.5, Claude Code.

Squashes:
- ea1a440 fixup! fix(fork-sync): read hook markers at the fork tip, not the replayed blob (#1510)

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 4, 2026
…e a trunk push (#1499)

## Problem

`fork:sync` pushes the trunk after its battery, and the battery ran no `hyprws CI` test job.
A red suite reached `hyprws` on three syncs (#1327).
On the 2026-10-02 sync a green dry-run battery hid a red server suite.

## Change

| Part | Change |
| --- | --- |
| `scripts/lib/fork-ci-jobs.ts` | new: reads every `test*` job from `hyprws-ci.yml` and expands matrix cells |
| `runChecks` | runs `checkCommands`, then every derived job; red job stops at its first red step |
| Report | `CheckRow.job` names the CI job; the error lists every red one |
| Env | umask `022`; scrubs `T3_*` and `T3CODE_*` |
| Sync workflow | `timeout-minutes` 60 to 90 |
| Docs | fork-sync guide gets a Check battery section; skill names `checks[].job` |

The driver does not hard-code the job list.
It throws on a step it cannot run as an exact `vp` argv.
It skips only `sudo apt-get` and `git` provisioning lines.
There is no skip flag, and a red row blocks the push.
Note: the battery also runs the scripts suite twice, once in `fork:ci` and once in Test Scripts.

## Scope and approval

Closes #1327.
The decision comment there sets the scope: a pre-push battery and no candidate branch.

## Close conditions

- [ ] **Unmoved:** red sync leaves the trunk alone
- [ ] **Named:** the report names the red suite
- [ ] **Guard:** a test fails on an unrun CI job
- [ ] **No skip:** no flag drops a job
- [ ] **Documented:** the fork-sync guide states it

## Verification

| Condition | Test |
| --- | --- |
| Unmoved, Named | `leaves the trunk alone and names the suite when one CI test job is red` |
| Guard | `runs every hyprws CI test job before a direct trunk push` |
| No skip | `takes no flag that drops a battery row` |
| Env | `runs the battery with CI's umask and none of the live T3 instance's environment` |

<details><summary>Commands</summary>

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
vp run --filter @t3tools/scripts typecheck → exit 0
vp test run fork-sync.test.ts lib/fork-ci-jobs.test.ts fork-gate-headers.test.ts → exit 0 (56 passed)

Each derived job, umask 022, T3_* and T3CODE_* unset:
Test          → exit 0
Test Web      → exit 0
Test Scripts  → exit 0
Test Server 1 → exit 0
Test Server 2 → exit 0
Test Server 3 → exit 0
```

</details>

Claude Opus 5.5 in Claude Code.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 4, 2026
…1510)

## Problem

The hourly sync onto `v0.0.45` rebases clean, then Test Server 3 goes red on every run:

```text
FAIL src/sourceControl/GitHubCli.test.ts > GitHubCli.listPullRequestsByHead > reads heads on one repository in one GraphQL document
SchemaError: Expected a valid JSON string
```

The sync step exports `GH_REPO`, and the check battery inherits it.
Upstream's `resolveBaseRepository` (`apps/server/src/sourceControl/GitHubCli.ts:817`) returns `null` whenever `GH_REPO` is set, so the lookup falls back to `gh pr list` with no stdin, and the test's GraphQL mock fails to decode it.
Trunk has the same failure under `GH_REPO`; it only surfaced once #1499 put the server shards in the battery, and trunk reached its current base from a local sync with no `GH_REPO`.

## Change

Drop `GH_REPO` from the `Run the sync driver` env in `.github/workflows/hyprws-upstream-sync.yml`.
Every `gh` call in the driver already passes `--repo`, so the variable did nothing for it.
The comment now says why the variable must stay out.

## Scope and approval

Part of #1505. Only a clean sync run closes that issue.
Landed as a `fixup!` of 06a999c, which could not fold there: #1504 rewrote the same lines later. Reworded in place to a standalone commit.

## Verification

| Tree | Env | Command | Result |
| --- | --- | --- | --- |
| Trunk rebased onto `v0.0.45` | `GH_REPO` set | `vp test run src/sourceControl/GitHubCli.test.ts` | exit 1, same `SchemaError` |
| Trunk rebased onto `v0.0.45` | none | same | exit 0, 24 passed |
| Trunk `646fa738cd4` | `GH_REPO` set | same | exit 1, same `SchemaError` |
| Trunk `646fa738cd4` | `GH_TOKEN` only | same | exit 0, 24 passed |

<details><summary>Shard and repo checks</summary>

Rebased copy, `vp run --filter t3 test --shard 3/3`:

```diff
- GH_TOKEN + GH_REPO (old step env): exit 1, 1 failed | 142 passed | 1 skipped (144)
+ GH_TOKEN only (new step env):      exit 0, 143 passed | 1 skipped (144)
```

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
```

</details>

Claude Opus 5.5, Claude Code.

Squashes:
- ea1a440 fixup! fix(fork-sync): read hook markers at the fork tip, not the replayed blob (#1510)

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 6, 2026
…e a trunk push (#1499)

## Problem

`fork:sync` pushes the trunk after its battery, and the battery ran no `hyprws CI` test job.
A red suite reached `hyprws` on three syncs (#1327).
On the 2026-10-02 sync a green dry-run battery hid a red server suite.

## Change

| Part | Change |
| --- | --- |
| `scripts/lib/fork-ci-jobs.ts` | new: reads every `test*` job from `hyprws-ci.yml` and expands matrix cells |
| `runChecks` | runs `checkCommands`, then every derived job; red job stops at its first red step |
| Report | `CheckRow.job` names the CI job; the error lists every red one |
| Env | umask `022`; scrubs `T3_*` and `T3CODE_*` |
| Sync workflow | `timeout-minutes` 60 to 90 |
| Docs | fork-sync guide gets a Check battery section; skill names `checks[].job` |

The driver does not hard-code the job list.
It throws on a step it cannot run as an exact `vp` argv.
It skips only `sudo apt-get` and `git` provisioning lines.
There is no skip flag, and a red row blocks the push.
Note: the battery also runs the scripts suite twice, once in `fork:ci` and once in Test Scripts.

## Scope and approval

Closes #1327.
The decision comment there sets the scope: a pre-push battery and no candidate branch.

## Close conditions

- [ ] **Unmoved:** red sync leaves the trunk alone
- [ ] **Named:** the report names the red suite
- [ ] **Guard:** a test fails on an unrun CI job
- [ ] **No skip:** no flag drops a job
- [ ] **Documented:** the fork-sync guide states it

## Verification

| Condition | Test |
| --- | --- |
| Unmoved, Named | `leaves the trunk alone and names the suite when one CI test job is red` |
| Guard | `runs every hyprws CI test job before a direct trunk push` |
| No skip | `takes no flag that drops a battery row` |
| Env | `runs the battery with CI's umask and none of the live T3 instance's environment` |

<details><summary>Commands</summary>

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
vp run --filter @t3tools/scripts typecheck → exit 0
vp test run fork-sync.test.ts lib/fork-ci-jobs.test.ts fork-gate-headers.test.ts → exit 0 (56 passed)

Each derived job, umask 022, T3_* and T3CODE_* unset:
Test          → exit 0
Test Web      → exit 0
Test Scripts  → exit 0
Test Server 1 → exit 0
Test Server 2 → exit 0
Test Server 3 → exit 0
```

</details>

Claude Opus 5.5 in Claude Code.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 11, 2026
…e a trunk push (#1499)

## Problem

`fork:sync` pushes the trunk after its battery, and the battery ran no `hyprws CI` test job.
A red suite reached `hyprws` on three syncs (#1327).
On the 2026-10-02 sync a green dry-run battery hid a red server suite.

## Change

| Part | Change |
| --- | --- |
| `scripts/lib/fork-ci-jobs.ts` | new: reads every `test*` job from `hyprws-ci.yml` and expands matrix cells |
| `runChecks` | runs `checkCommands`, then every derived job; red job stops at its first red step |
| Report | `CheckRow.job` names the CI job; the error lists every red one |
| Env | umask `022`; scrubs `T3_*` and `T3CODE_*` |
| Sync workflow | `timeout-minutes` 60 to 90 |
| Docs | fork-sync guide gets a Check battery section; skill names `checks[].job` |

The driver does not hard-code the job list.
It throws on a step it cannot run as an exact `vp` argv.
It skips only `sudo apt-get` and `git` provisioning lines.
There is no skip flag, and a red row blocks the push.
Note: the battery also runs the scripts suite twice, once in `fork:ci` and once in Test Scripts.

## Scope and approval

Closes #1327.
The decision comment there sets the scope: a pre-push battery and no candidate branch.

## Close conditions

- [ ] **Unmoved:** red sync leaves the trunk alone
- [ ] **Named:** the report names the red suite
- [ ] **Guard:** a test fails on an unrun CI job
- [ ] **No skip:** no flag drops a job
- [ ] **Documented:** the fork-sync guide states it

## Verification

| Condition | Test |
| --- | --- |
| Unmoved, Named | `leaves the trunk alone and names the suite when one CI test job is red` |
| Guard | `runs every hyprws CI test job before a direct trunk push` |
| No skip | `takes no flag that drops a battery row` |
| Env | `runs the battery with CI's umask and none of the live T3 instance's environment` |

<details><summary>Commands</summary>

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
vp run --filter @t3tools/scripts typecheck → exit 0
vp test run fork-sync.test.ts lib/fork-ci-jobs.test.ts fork-gate-headers.test.ts → exit 0 (56 passed)

Each derived job, umask 022, T3_* and T3CODE_* unset:
Test          → exit 0
Test Web      → exit 0
Test Scripts  → exit 0
Test Server 1 → exit 0
Test Server 2 → exit 0
Test Server 3 → exit 0
```

</details>

Claude Opus 5.5 in Claude Code.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 11, 2026
…1510)

## Problem

The hourly sync onto `v0.0.45` rebases clean, then Test Server 3 goes red on every run:

```text
FAIL src/sourceControl/GitHubCli.test.ts > GitHubCli.listPullRequestsByHead > reads heads on one repository in one GraphQL document
SchemaError: Expected a valid JSON string
```

The sync step exports `GH_REPO`, and the check battery inherits it.
Upstream's `resolveBaseRepository` (`apps/server/src/sourceControl/GitHubCli.ts:817`) returns `null` whenever `GH_REPO` is set, so the lookup falls back to `gh pr list` with no stdin, and the test's GraphQL mock fails to decode it.
Trunk has the same failure under `GH_REPO`; it only surfaced once #1499 put the server shards in the battery, and trunk reached its current base from a local sync with no `GH_REPO`.

## Change

Drop `GH_REPO` from the `Run the sync driver` env in `.github/workflows/hyprws-upstream-sync.yml`.
Every `gh` call in the driver already passes `--repo`, so the variable did nothing for it.
The comment now says why the variable must stay out.

## Scope and approval

Part of #1505. Only a clean sync run closes that issue.
Landed as a `fixup!` of 06a999c, which could not fold there: #1504 rewrote the same lines later. Reworded in place to a standalone commit.

## Verification

| Tree | Env | Command | Result |
| --- | --- | --- | --- |
| Trunk rebased onto `v0.0.45` | `GH_REPO` set | `vp test run src/sourceControl/GitHubCli.test.ts` | exit 1, same `SchemaError` |
| Trunk rebased onto `v0.0.45` | none | same | exit 0, 24 passed |
| Trunk `646fa738cd4` | `GH_REPO` set | same | exit 1, same `SchemaError` |
| Trunk `646fa738cd4` | `GH_TOKEN` only | same | exit 0, 24 passed |

<details><summary>Shard and repo checks</summary>

Rebased copy, `vp run --filter t3 test --shard 3/3`:

```diff
- GH_TOKEN + GH_REPO (old step env): exit 1, 1 failed | 142 passed | 1 skipped (144)
+ GH_TOKEN only (new step env):      exit 0, 143 passed | 1 skipped (144)
```

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
```

</details>

Claude Opus 5.5, Claude Code.

Squashes:
- ea1a440 fixup! fix(fork-sync): read hook markers at the fork tip, not the replayed blob (#1510)

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 11, 2026
…e a trunk push (#1499)

## Problem

`fork:sync` pushes the trunk after its battery, and the battery ran no `hyprws CI` test job.
A red suite reached `hyprws` on three syncs (#1327).
On the 2026-10-02 sync a green dry-run battery hid a red server suite.

## Change

| Part | Change |
| --- | --- |
| `scripts/lib/fork-ci-jobs.ts` | new: reads every `test*` job from `hyprws-ci.yml` and expands matrix cells |
| `runChecks` | runs `checkCommands`, then every derived job; red job stops at its first red step |
| Report | `CheckRow.job` names the CI job; the error lists every red one |
| Env | umask `022`; scrubs `T3_*` and `T3CODE_*` |
| Sync workflow | `timeout-minutes` 60 to 90 |
| Docs | fork-sync guide gets a Check battery section; skill names `checks[].job` |

The driver does not hard-code the job list.
It throws on a step it cannot run as an exact `vp` argv.
It skips only `sudo apt-get` and `git` provisioning lines.
There is no skip flag, and a red row blocks the push.
Note: the battery also runs the scripts suite twice, once in `fork:ci` and once in Test Scripts.

## Scope and approval

Closes #1327.
The decision comment there sets the scope: a pre-push battery and no candidate branch.

## Close conditions

- [ ] **Unmoved:** red sync leaves the trunk alone
- [ ] **Named:** the report names the red suite
- [ ] **Guard:** a test fails on an unrun CI job
- [ ] **No skip:** no flag drops a job
- [ ] **Documented:** the fork-sync guide states it

## Verification

| Condition | Test |
| --- | --- |
| Unmoved, Named | `leaves the trunk alone and names the suite when one CI test job is red` |
| Guard | `runs every hyprws CI test job before a direct trunk push` |
| No skip | `takes no flag that drops a battery row` |
| Env | `runs the battery with CI's umask and none of the live T3 instance's environment` |

<details><summary>Commands</summary>

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
vp run --filter @t3tools/scripts typecheck → exit 0
vp test run fork-sync.test.ts lib/fork-ci-jobs.test.ts fork-gate-headers.test.ts → exit 0 (56 passed)

Each derived job, umask 022, T3_* and T3CODE_* unset:
Test          → exit 0
Test Web      → exit 0
Test Scripts  → exit 0
Test Server 1 → exit 0
Test Server 2 → exit 0
Test Server 3 → exit 0
```

</details>

Claude Opus 5.5 in Claude Code.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 11, 2026
…1510)

## Problem

The hourly sync onto `v0.0.45` rebases clean, then Test Server 3 goes red on every run:

```text
FAIL src/sourceControl/GitHubCli.test.ts > GitHubCli.listPullRequestsByHead > reads heads on one repository in one GraphQL document
SchemaError: Expected a valid JSON string
```

The sync step exports `GH_REPO`, and the check battery inherits it.
Upstream's `resolveBaseRepository` (`apps/server/src/sourceControl/GitHubCli.ts:817`) returns `null` whenever `GH_REPO` is set, so the lookup falls back to `gh pr list` with no stdin, and the test's GraphQL mock fails to decode it.
Trunk has the same failure under `GH_REPO`; it only surfaced once #1499 put the server shards in the battery, and trunk reached its current base from a local sync with no `GH_REPO`.

## Change

Drop `GH_REPO` from the `Run the sync driver` env in `.github/workflows/hyprws-upstream-sync.yml`.
Every `gh` call in the driver already passes `--repo`, so the variable did nothing for it.
The comment now says why the variable must stay out.

## Scope and approval

Part of #1505. Only a clean sync run closes that issue.
Landed as a `fixup!` of 06a999c, which could not fold there: #1504 rewrote the same lines later. Reworded in place to a standalone commit.

## Verification

| Tree | Env | Command | Result |
| --- | --- | --- | --- |
| Trunk rebased onto `v0.0.45` | `GH_REPO` set | `vp test run src/sourceControl/GitHubCli.test.ts` | exit 1, same `SchemaError` |
| Trunk rebased onto `v0.0.45` | none | same | exit 0, 24 passed |
| Trunk `646fa738cd4` | `GH_REPO` set | same | exit 1, same `SchemaError` |
| Trunk `646fa738cd4` | `GH_TOKEN` only | same | exit 0, 24 passed |

<details><summary>Shard and repo checks</summary>

Rebased copy, `vp run --filter t3 test --shard 3/3`:

```diff
- GH_TOKEN + GH_REPO (old step env): exit 1, 1 failed | 142 passed | 1 skipped (144)
+ GH_TOKEN only (new step env):      exit 0, 143 passed | 1 skipped (144)
```

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
```

</details>

Claude Opus 5.5, Claude Code.

Squashes:
- ea1a440 fixup! fix(fork-sync): read hook markers at the fork tip, not the replayed blob (#1510)

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 12, 2026
…e a trunk push (#1499)

## Problem

`fork:sync` pushes the trunk after its battery, and the battery ran no `hyprws CI` test job.
A red suite reached `hyprws` on three syncs (#1327).
On the 2026-10-02 sync a green dry-run battery hid a red server suite.

## Change

| Part | Change |
| --- | --- |
| `scripts/lib/fork-ci-jobs.ts` | new: reads every `test*` job from `hyprws-ci.yml` and expands matrix cells |
| `runChecks` | runs `checkCommands`, then every derived job; red job stops at its first red step |
| Report | `CheckRow.job` names the CI job; the error lists every red one |
| Env | umask `022`; scrubs `T3_*` and `T3CODE_*` |
| Sync workflow | `timeout-minutes` 60 to 90 |
| Docs | fork-sync guide gets a Check battery section; skill names `checks[].job` |

The driver does not hard-code the job list.
It throws on a step it cannot run as an exact `vp` argv.
It skips only `sudo apt-get` and `git` provisioning lines.
There is no skip flag, and a red row blocks the push.
Note: the battery also runs the scripts suite twice, once in `fork:ci` and once in Test Scripts.

## Scope and approval

Closes #1327.
The decision comment there sets the scope: a pre-push battery and no candidate branch.

## Close conditions

- [ ] **Unmoved:** red sync leaves the trunk alone
- [ ] **Named:** the report names the red suite
- [ ] **Guard:** a test fails on an unrun CI job
- [ ] **No skip:** no flag drops a job
- [ ] **Documented:** the fork-sync guide states it

## Verification

| Condition | Test |
| --- | --- |
| Unmoved, Named | `leaves the trunk alone and names the suite when one CI test job is red` |
| Guard | `runs every hyprws CI test job before a direct trunk push` |
| No skip | `takes no flag that drops a battery row` |
| Env | `runs the battery with CI's umask and none of the live T3 instance's environment` |

<details><summary>Commands</summary>

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
vp run --filter @t3tools/scripts typecheck → exit 0
vp test run fork-sync.test.ts lib/fork-ci-jobs.test.ts fork-gate-headers.test.ts → exit 0 (56 passed)

Each derived job, umask 022, T3_* and T3CODE_* unset:
Test          → exit 0
Test Web      → exit 0
Test Scripts  → exit 0
Test Server 1 → exit 0
Test Server 2 → exit 0
Test Server 3 → exit 0
```

</details>

Claude Opus 5.5 in Claude Code.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 12, 2026
…1510)

## Problem

The hourly sync onto `v0.0.45` rebases clean, then Test Server 3 goes red on every run:

```text
FAIL src/sourceControl/GitHubCli.test.ts > GitHubCli.listPullRequestsByHead > reads heads on one repository in one GraphQL document
SchemaError: Expected a valid JSON string
```

The sync step exports `GH_REPO`, and the check battery inherits it.
Upstream's `resolveBaseRepository` (`apps/server/src/sourceControl/GitHubCli.ts:817`) returns `null` whenever `GH_REPO` is set, so the lookup falls back to `gh pr list` with no stdin, and the test's GraphQL mock fails to decode it.
Trunk has the same failure under `GH_REPO`; it only surfaced once #1499 put the server shards in the battery, and trunk reached its current base from a local sync with no `GH_REPO`.

## Change

Drop `GH_REPO` from the `Run the sync driver` env in `.github/workflows/hyprws-upstream-sync.yml`.
Every `gh` call in the driver already passes `--repo`, so the variable did nothing for it.
The comment now says why the variable must stay out.

## Scope and approval

Part of #1505. Only a clean sync run closes that issue.
Landed as a `fixup!` of 06a999c, which could not fold there: #1504 rewrote the same lines later. Reworded in place to a standalone commit.

## Verification

| Tree | Env | Command | Result |
| --- | --- | --- | --- |
| Trunk rebased onto `v0.0.45` | `GH_REPO` set | `vp test run src/sourceControl/GitHubCli.test.ts` | exit 1, same `SchemaError` |
| Trunk rebased onto `v0.0.45` | none | same | exit 0, 24 passed |
| Trunk `646fa738cd4` | `GH_REPO` set | same | exit 1, same `SchemaError` |
| Trunk `646fa738cd4` | `GH_TOKEN` only | same | exit 0, 24 passed |

<details><summary>Shard and repo checks</summary>

Rebased copy, `vp run --filter t3 test --shard 3/3`:

```diff
- GH_TOKEN + GH_REPO (old step env): exit 1, 1 failed | 142 passed | 1 skipped (144)
+ GH_TOKEN only (new step env):      exit 0, 143 passed | 1 skipped (144)
```

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
```

</details>

Claude Opus 5.5, Claude Code.

Squashes:
- ea1a440 fixup! fix(fork-sync): read hook markers at the fork tip, not the replayed blob (#1510)

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 12, 2026
…e a trunk push (#1499)

## Problem

`fork:sync` pushes the trunk after its battery, and the battery ran no `hyprws CI` test job.
A red suite reached `hyprws` on three syncs (#1327).
On the 2026-10-02 sync a green dry-run battery hid a red server suite.

## Change

| Part | Change |
| --- | --- |
| `scripts/lib/fork-ci-jobs.ts` | new: reads every `test*` job from `hyprws-ci.yml` and expands matrix cells |
| `runChecks` | runs `checkCommands`, then every derived job; red job stops at its first red step |
| Report | `CheckRow.job` names the CI job; the error lists every red one |
| Env | umask `022`; scrubs `T3_*` and `T3CODE_*` |
| Sync workflow | `timeout-minutes` 60 to 90 |
| Docs | fork-sync guide gets a Check battery section; skill names `checks[].job` |

The driver does not hard-code the job list.
It throws on a step it cannot run as an exact `vp` argv.
It skips only `sudo apt-get` and `git` provisioning lines.
There is no skip flag, and a red row blocks the push.
Note: the battery also runs the scripts suite twice, once in `fork:ci` and once in Test Scripts.

## Scope and approval

Closes #1327.
The decision comment there sets the scope: a pre-push battery and no candidate branch.

## Close conditions

- [ ] **Unmoved:** red sync leaves the trunk alone
- [ ] **Named:** the report names the red suite
- [ ] **Guard:** a test fails on an unrun CI job
- [ ] **No skip:** no flag drops a job
- [ ] **Documented:** the fork-sync guide states it

## Verification

| Condition | Test |
| --- | --- |
| Unmoved, Named | `leaves the trunk alone and names the suite when one CI test job is red` |
| Guard | `runs every hyprws CI test job before a direct trunk push` |
| No skip | `takes no flag that drops a battery row` |
| Env | `runs the battery with CI's umask and none of the live T3 instance's environment` |

<details><summary>Commands</summary>

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
vp run --filter @t3tools/scripts typecheck → exit 0
vp test run fork-sync.test.ts lib/fork-ci-jobs.test.ts fork-gate-headers.test.ts → exit 0 (56 passed)

Each derived job, umask 022, T3_* and T3CODE_* unset:
Test          → exit 0
Test Web      → exit 0
Test Scripts  → exit 0
Test Server 1 → exit 0
Test Server 2 → exit 0
Test Server 3 → exit 0
```

</details>

Claude Opus 5.5 in Claude Code.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 12, 2026
…1510)

## Problem

The hourly sync onto `v0.0.45` rebases clean, then Test Server 3 goes red on every run:

```text
FAIL src/sourceControl/GitHubCli.test.ts > GitHubCli.listPullRequestsByHead > reads heads on one repository in one GraphQL document
SchemaError: Expected a valid JSON string
```

The sync step exports `GH_REPO`, and the check battery inherits it.
Upstream's `resolveBaseRepository` (`apps/server/src/sourceControl/GitHubCli.ts:817`) returns `null` whenever `GH_REPO` is set, so the lookup falls back to `gh pr list` with no stdin, and the test's GraphQL mock fails to decode it.
Trunk has the same failure under `GH_REPO`; it only surfaced once #1499 put the server shards in the battery, and trunk reached its current base from a local sync with no `GH_REPO`.

## Change

Drop `GH_REPO` from the `Run the sync driver` env in `.github/workflows/hyprws-upstream-sync.yml`.
Every `gh` call in the driver already passes `--repo`, so the variable did nothing for it.
The comment now says why the variable must stay out.

## Scope and approval

Part of #1505. Only a clean sync run closes that issue.
Landed as a `fixup!` of 06a999c, which could not fold there: #1504 rewrote the same lines later. Reworded in place to a standalone commit.

## Verification

| Tree | Env | Command | Result |
| --- | --- | --- | --- |
| Trunk rebased onto `v0.0.45` | `GH_REPO` set | `vp test run src/sourceControl/GitHubCli.test.ts` | exit 1, same `SchemaError` |
| Trunk rebased onto `v0.0.45` | none | same | exit 0, 24 passed |
| Trunk `646fa738cd4` | `GH_REPO` set | same | exit 1, same `SchemaError` |
| Trunk `646fa738cd4` | `GH_TOKEN` only | same | exit 0, 24 passed |

<details><summary>Shard and repo checks</summary>

Rebased copy, `vp run --filter t3 test --shard 3/3`:

```diff
- GH_TOKEN + GH_REPO (old step env): exit 1, 1 failed | 142 passed | 1 skipped (144)
+ GH_TOKEN only (new step env):      exit 0, 143 passed | 1 skipped (144)
```

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
```

</details>

Claude Opus 5.5, Claude Code.

Squashes:
- ea1a440 fixup! fix(fork-sync): read hook markers at the fork tip, not the replayed blob (#1510)

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 13, 2026
…e a trunk push (#1499)

## Problem

`fork:sync` pushes the trunk after its battery, and the battery ran no `hyprws CI` test job.
A red suite reached `hyprws` on three syncs (#1327).
On the 2026-10-02 sync a green dry-run battery hid a red server suite.

## Change

| Part | Change |
| --- | --- |
| `scripts/lib/fork-ci-jobs.ts` | new: reads every `test*` job from `hyprws-ci.yml` and expands matrix cells |
| `runChecks` | runs `checkCommands`, then every derived job; red job stops at its first red step |
| Report | `CheckRow.job` names the CI job; the error lists every red one |
| Env | umask `022`; scrubs `T3_*` and `T3CODE_*` |
| Sync workflow | `timeout-minutes` 60 to 90 |
| Docs | fork-sync guide gets a Check battery section; skill names `checks[].job` |

The driver does not hard-code the job list.
It throws on a step it cannot run as an exact `vp` argv.
It skips only `sudo apt-get` and `git` provisioning lines.
There is no skip flag, and a red row blocks the push.
Note: the battery also runs the scripts suite twice, once in `fork:ci` and once in Test Scripts.

## Scope and approval

Closes #1327.
The decision comment there sets the scope: a pre-push battery and no candidate branch.

## Close conditions

- [ ] **Unmoved:** red sync leaves the trunk alone
- [ ] **Named:** the report names the red suite
- [ ] **Guard:** a test fails on an unrun CI job
- [ ] **No skip:** no flag drops a job
- [ ] **Documented:** the fork-sync guide states it

## Verification

| Condition | Test |
| --- | --- |
| Unmoved, Named | `leaves the trunk alone and names the suite when one CI test job is red` |
| Guard | `runs every hyprws CI test job before a direct trunk push` |
| No skip | `takes no flag that drops a battery row` |
| Env | `runs the battery with CI's umask and none of the live T3 instance's environment` |

<details><summary>Commands</summary>

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
vp run --filter @t3tools/scripts typecheck → exit 0
vp test run fork-sync.test.ts lib/fork-ci-jobs.test.ts fork-gate-headers.test.ts → exit 0 (56 passed)

Each derived job, umask 022, T3_* and T3CODE_* unset:
Test          → exit 0
Test Web      → exit 0
Test Scripts  → exit 0
Test Server 1 → exit 0
Test Server 2 → exit 0
Test Server 3 → exit 0
```

</details>

Claude Opus 5.5 in Claude Code.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 13, 2026
…1510)

## Problem

The hourly sync onto `v0.0.45` rebases clean, then Test Server 3 goes red on every run:

```text
FAIL src/sourceControl/GitHubCli.test.ts > GitHubCli.listPullRequestsByHead > reads heads on one repository in one GraphQL document
SchemaError: Expected a valid JSON string
```

The sync step exports `GH_REPO`, and the check battery inherits it.
Upstream's `resolveBaseRepository` (`apps/server/src/sourceControl/GitHubCli.ts:817`) returns `null` whenever `GH_REPO` is set, so the lookup falls back to `gh pr list` with no stdin, and the test's GraphQL mock fails to decode it.
Trunk has the same failure under `GH_REPO`; it only surfaced once #1499 put the server shards in the battery, and trunk reached its current base from a local sync with no `GH_REPO`.

## Change

Drop `GH_REPO` from the `Run the sync driver` env in `.github/workflows/hyprws-upstream-sync.yml`.
Every `gh` call in the driver already passes `--repo`, so the variable did nothing for it.
The comment now says why the variable must stay out.

## Scope and approval

Part of #1505. Only a clean sync run closes that issue.
Landed as a `fixup!` of 06a999c, which could not fold there: #1504 rewrote the same lines later. Reworded in place to a standalone commit.

## Verification

| Tree | Env | Command | Result |
| --- | --- | --- | --- |
| Trunk rebased onto `v0.0.45` | `GH_REPO` set | `vp test run src/sourceControl/GitHubCli.test.ts` | exit 1, same `SchemaError` |
| Trunk rebased onto `v0.0.45` | none | same | exit 0, 24 passed |
| Trunk `646fa738cd4` | `GH_REPO` set | same | exit 1, same `SchemaError` |
| Trunk `646fa738cd4` | `GH_TOKEN` only | same | exit 0, 24 passed |

<details><summary>Shard and repo checks</summary>

Rebased copy, `vp run --filter t3 test --shard 3/3`:

```diff
- GH_TOKEN + GH_REPO (old step env): exit 1, 1 failed | 142 passed | 1 skipped (144)
+ GH_TOKEN only (new step env):      exit 0, 143 passed | 1 skipped (144)
```

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
```

</details>

Claude Opus 5.5, Claude Code.

Squashes:
- ea1a440 fixup! fix(fork-sync): read hook markers at the fork tip, not the replayed blob (#1510)

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 15, 2026
…e a trunk push (#1499)

## Problem

`fork:sync` pushes the trunk after its battery, and the battery ran no `hyprws CI` test job.
A red suite reached `hyprws` on three syncs (#1327).
On the 2026-10-02 sync a green dry-run battery hid a red server suite.

## Change

| Part | Change |
| --- | --- |
| `scripts/lib/fork-ci-jobs.ts` | new: reads every `test*` job from `hyprws-ci.yml` and expands matrix cells |
| `runChecks` | runs `checkCommands`, then every derived job; red job stops at its first red step |
| Report | `CheckRow.job` names the CI job; the error lists every red one |
| Env | umask `022`; scrubs `T3_*` and `T3CODE_*` |
| Sync workflow | `timeout-minutes` 60 to 90 |
| Docs | fork-sync guide gets a Check battery section; skill names `checks[].job` |

The driver does not hard-code the job list.
It throws on a step it cannot run as an exact `vp` argv.
It skips only `sudo apt-get` and `git` provisioning lines.
There is no skip flag, and a red row blocks the push.
Note: the battery also runs the scripts suite twice, once in `fork:ci` and once in Test Scripts.

## Scope and approval

Closes #1327.
The decision comment there sets the scope: a pre-push battery and no candidate branch.

## Close conditions

- [ ] **Unmoved:** red sync leaves the trunk alone
- [ ] **Named:** the report names the red suite
- [ ] **Guard:** a test fails on an unrun CI job
- [ ] **No skip:** no flag drops a job
- [ ] **Documented:** the fork-sync guide states it

## Verification

| Condition | Test |
| --- | --- |
| Unmoved, Named | `leaves the trunk alone and names the suite when one CI test job is red` |
| Guard | `runs every hyprws CI test job before a direct trunk push` |
| No skip | `takes no flag that drops a battery row` |
| Env | `runs the battery with CI's umask and none of the live T3 instance's environment` |

<details><summary>Commands</summary>

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
vp run --filter @t3tools/scripts typecheck → exit 0
vp test run fork-sync.test.ts lib/fork-ci-jobs.test.ts fork-gate-headers.test.ts → exit 0 (56 passed)

Each derived job, umask 022, T3_* and T3CODE_* unset:
Test          → exit 0
Test Web      → exit 0
Test Scripts  → exit 0
Test Server 1 → exit 0
Test Server 2 → exit 0
Test Server 3 → exit 0
```

</details>

Claude Opus 5.5 in Claude Code.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 15, 2026
…1510)

## Problem

The hourly sync onto `v0.0.45` rebases clean, then Test Server 3 goes red on every run:

```text
FAIL src/sourceControl/GitHubCli.test.ts > GitHubCli.listPullRequestsByHead > reads heads on one repository in one GraphQL document
SchemaError: Expected a valid JSON string
```

The sync step exports `GH_REPO`, and the check battery inherits it.
Upstream's `resolveBaseRepository` (`apps/server/src/sourceControl/GitHubCli.ts:817`) returns `null` whenever `GH_REPO` is set, so the lookup falls back to `gh pr list` with no stdin, and the test's GraphQL mock fails to decode it.
Trunk has the same failure under `GH_REPO`; it only surfaced once #1499 put the server shards in the battery, and trunk reached its current base from a local sync with no `GH_REPO`.

## Change

Drop `GH_REPO` from the `Run the sync driver` env in `.github/workflows/hyprws-upstream-sync.yml`.
Every `gh` call in the driver already passes `--repo`, so the variable did nothing for it.
The comment now says why the variable must stay out.

## Scope and approval

Part of #1505. Only a clean sync run closes that issue.
Landed as a `fixup!` of 06a999c, which could not fold there: #1504 rewrote the same lines later. Reworded in place to a standalone commit.

## Verification

| Tree | Env | Command | Result |
| --- | --- | --- | --- |
| Trunk rebased onto `v0.0.45` | `GH_REPO` set | `vp test run src/sourceControl/GitHubCli.test.ts` | exit 1, same `SchemaError` |
| Trunk rebased onto `v0.0.45` | none | same | exit 0, 24 passed |
| Trunk `646fa738cd4` | `GH_REPO` set | same | exit 1, same `SchemaError` |
| Trunk `646fa738cd4` | `GH_TOKEN` only | same | exit 0, 24 passed |

<details><summary>Shard and repo checks</summary>

Rebased copy, `vp run --filter t3 test --shard 3/3`:

```diff
- GH_TOKEN + GH_REPO (old step env): exit 1, 1 failed | 142 passed | 1 skipped (144)
+ GH_TOKEN only (new step env):      exit 0, 143 passed | 1 skipped (144)
```

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
```

</details>

Claude Opus 5.5, Claude Code.

Squashes:
- ea1a440 fixup! fix(fork-sync): read hook markers at the fork tip, not the replayed blob (#1510)

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 15, 2026
…e a trunk push (#1499)

## Problem

`fork:sync` pushes the trunk after its battery, and the battery ran no `hyprws CI` test job.
A red suite reached `hyprws` on three syncs (#1327).
On the 2026-10-02 sync a green dry-run battery hid a red server suite.

## Change

| Part | Change |
| --- | --- |
| `scripts/lib/fork-ci-jobs.ts` | new: reads every `test*` job from `hyprws-ci.yml` and expands matrix cells |
| `runChecks` | runs `checkCommands`, then every derived job; red job stops at its first red step |
| Report | `CheckRow.job` names the CI job; the error lists every red one |
| Env | umask `022`; scrubs `T3_*` and `T3CODE_*` |
| Sync workflow | `timeout-minutes` 60 to 90 |
| Docs | fork-sync guide gets a Check battery section; skill names `checks[].job` |

The driver does not hard-code the job list.
It throws on a step it cannot run as an exact `vp` argv.
It skips only `sudo apt-get` and `git` provisioning lines.
There is no skip flag, and a red row blocks the push.
Note: the battery also runs the scripts suite twice, once in `fork:ci` and once in Test Scripts.

## Scope and approval

Closes #1327.
The decision comment there sets the scope: a pre-push battery and no candidate branch.

## Close conditions

- [ ] **Unmoved:** red sync leaves the trunk alone
- [ ] **Named:** the report names the red suite
- [ ] **Guard:** a test fails on an unrun CI job
- [ ] **No skip:** no flag drops a job
- [ ] **Documented:** the fork-sync guide states it

## Verification

| Condition | Test |
| --- | --- |
| Unmoved, Named | `leaves the trunk alone and names the suite when one CI test job is red` |
| Guard | `runs every hyprws CI test job before a direct trunk push` |
| No skip | `takes no flag that drops a battery row` |
| Env | `runs the battery with CI's umask and none of the live T3 instance's environment` |

<details><summary>Commands</summary>

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
vp run --filter @t3tools/scripts typecheck → exit 0
vp test run fork-sync.test.ts lib/fork-ci-jobs.test.ts fork-gate-headers.test.ts → exit 0 (56 passed)

Each derived job, umask 022, T3_* and T3CODE_* unset:
Test          → exit 0
Test Web      → exit 0
Test Scripts  → exit 0
Test Server 1 → exit 0
Test Server 2 → exit 0
Test Server 3 → exit 0
```

</details>

Claude Opus 5.5 in Claude Code.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 15, 2026
…1510)

## Problem

The hourly sync onto `v0.0.45` rebases clean, then Test Server 3 goes red on every run:

```text
FAIL src/sourceControl/GitHubCli.test.ts > GitHubCli.listPullRequestsByHead > reads heads on one repository in one GraphQL document
SchemaError: Expected a valid JSON string
```

The sync step exports `GH_REPO`, and the check battery inherits it.
Upstream's `resolveBaseRepository` (`apps/server/src/sourceControl/GitHubCli.ts:817`) returns `null` whenever `GH_REPO` is set, so the lookup falls back to `gh pr list` with no stdin, and the test's GraphQL mock fails to decode it.
Trunk has the same failure under `GH_REPO`; it only surfaced once #1499 put the server shards in the battery, and trunk reached its current base from a local sync with no `GH_REPO`.

## Change

Drop `GH_REPO` from the `Run the sync driver` env in `.github/workflows/hyprws-upstream-sync.yml`.
Every `gh` call in the driver already passes `--repo`, so the variable did nothing for it.
The comment now says why the variable must stay out.

## Scope and approval

Part of #1505. Only a clean sync run closes that issue.
Landed as a `fixup!` of 06a999c, which could not fold there: #1504 rewrote the same lines later. Reworded in place to a standalone commit.

## Verification

| Tree | Env | Command | Result |
| --- | --- | --- | --- |
| Trunk rebased onto `v0.0.45` | `GH_REPO` set | `vp test run src/sourceControl/GitHubCli.test.ts` | exit 1, same `SchemaError` |
| Trunk rebased onto `v0.0.45` | none | same | exit 0, 24 passed |
| Trunk `646fa738cd4` | `GH_REPO` set | same | exit 1, same `SchemaError` |
| Trunk `646fa738cd4` | `GH_TOKEN` only | same | exit 0, 24 passed |

<details><summary>Shard and repo checks</summary>

Rebased copy, `vp run --filter t3 test --shard 3/3`:

```diff
- GH_TOKEN + GH_REPO (old step env): exit 1, 1 failed | 142 passed | 1 skipped (144)
+ GH_TOKEN only (new step env):      exit 0, 143 passed | 1 skipped (144)
```

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
```

</details>

Claude Opus 5.5, Claude Code.

Squashes:
- ea1a440 fixup! fix(fork-sync): read hook markers at the fork tip, not the replayed blob (#1510)

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 16, 2026
…e a trunk push (#1499)

## Problem

`fork:sync` pushes the trunk after its battery, and the battery ran no `hyprws CI` test job.
A red suite reached `hyprws` on three syncs (#1327).
On the 2026-10-02 sync a green dry-run battery hid a red server suite.

## Change

| Part | Change |
| --- | --- |
| `scripts/lib/fork-ci-jobs.ts` | new: reads every `test*` job from `hyprws-ci.yml` and expands matrix cells |
| `runChecks` | runs `checkCommands`, then every derived job; red job stops at its first red step |
| Report | `CheckRow.job` names the CI job; the error lists every red one |
| Env | umask `022`; scrubs `T3_*` and `T3CODE_*` |
| Sync workflow | `timeout-minutes` 60 to 90 |
| Docs | fork-sync guide gets a Check battery section; skill names `checks[].job` |

The driver does not hard-code the job list.
It throws on a step it cannot run as an exact `vp` argv.
It skips only `sudo apt-get` and `git` provisioning lines.
There is no skip flag, and a red row blocks the push.
Note: the battery also runs the scripts suite twice, once in `fork:ci` and once in Test Scripts.

## Scope and approval

Closes #1327.
The decision comment there sets the scope: a pre-push battery and no candidate branch.

## Close conditions

- [ ] **Unmoved:** red sync leaves the trunk alone
- [ ] **Named:** the report names the red suite
- [ ] **Guard:** a test fails on an unrun CI job
- [ ] **No skip:** no flag drops a job
- [ ] **Documented:** the fork-sync guide states it

## Verification

| Condition | Test |
| --- | --- |
| Unmoved, Named | `leaves the trunk alone and names the suite when one CI test job is red` |
| Guard | `runs every hyprws CI test job before a direct trunk push` |
| No skip | `takes no flag that drops a battery row` |
| Env | `runs the battery with CI's umask and none of the live T3 instance's environment` |

<details><summary>Commands</summary>

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
vp run --filter @t3tools/scripts typecheck → exit 0
vp test run fork-sync.test.ts lib/fork-ci-jobs.test.ts fork-gate-headers.test.ts → exit 0 (56 passed)

Each derived job, umask 022, T3_* and T3CODE_* unset:
Test          → exit 0
Test Web      → exit 0
Test Scripts  → exit 0
Test Server 1 → exit 0
Test Server 2 → exit 0
Test Server 3 → exit 0
```

</details>

Claude Opus 5.5 in Claude Code.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 16, 2026
…1510)

## Problem

The hourly sync onto `v0.0.45` rebases clean, then Test Server 3 goes red on every run:

```text
FAIL src/sourceControl/GitHubCli.test.ts > GitHubCli.listPullRequestsByHead > reads heads on one repository in one GraphQL document
SchemaError: Expected a valid JSON string
```

The sync step exports `GH_REPO`, and the check battery inherits it.
Upstream's `resolveBaseRepository` (`apps/server/src/sourceControl/GitHubCli.ts:817`) returns `null` whenever `GH_REPO` is set, so the lookup falls back to `gh pr list` with no stdin, and the test's GraphQL mock fails to decode it.
Trunk has the same failure under `GH_REPO`; it only surfaced once #1499 put the server shards in the battery, and trunk reached its current base from a local sync with no `GH_REPO`.

## Change

Drop `GH_REPO` from the `Run the sync driver` env in `.github/workflows/hyprws-upstream-sync.yml`.
Every `gh` call in the driver already passes `--repo`, so the variable did nothing for it.
The comment now says why the variable must stay out.

## Scope and approval

Part of #1505. Only a clean sync run closes that issue.
Landed as a `fixup!` of 06a999c, which could not fold there: #1504 rewrote the same lines later. Reworded in place to a standalone commit.

## Verification

| Tree | Env | Command | Result |
| --- | --- | --- | --- |
| Trunk rebased onto `v0.0.45` | `GH_REPO` set | `vp test run src/sourceControl/GitHubCli.test.ts` | exit 1, same `SchemaError` |
| Trunk rebased onto `v0.0.45` | none | same | exit 0, 24 passed |
| Trunk `646fa738cd4` | `GH_REPO` set | same | exit 1, same `SchemaError` |
| Trunk `646fa738cd4` | `GH_TOKEN` only | same | exit 0, 24 passed |

<details><summary>Shard and repo checks</summary>

Rebased copy, `vp run --filter t3 test --shard 3/3`:

```diff
- GH_TOKEN + GH_REPO (old step env): exit 1, 1 failed | 142 passed | 1 skipped (144)
+ GH_TOKEN only (new step env):      exit 0, 143 passed | 1 skipped (144)
```

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
```

</details>

Claude Opus 5.5, Claude Code.

Squashes:
- ea1a440 fixup! fix(fork-sync): read hook markers at the fork tip, not the replayed blob (#1510)

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 16, 2026
…e a trunk push (#1499)

## Problem

`fork:sync` pushes the trunk after its battery, and the battery ran no `hyprws CI` test job.
A red suite reached `hyprws` on three syncs (#1327).
On the 2026-10-02 sync a green dry-run battery hid a red server suite.

## Change

| Part | Change |
| --- | --- |
| `scripts/lib/fork-ci-jobs.ts` | new: reads every `test*` job from `hyprws-ci.yml` and expands matrix cells |
| `runChecks` | runs `checkCommands`, then every derived job; red job stops at its first red step |
| Report | `CheckRow.job` names the CI job; the error lists every red one |
| Env | umask `022`; scrubs `T3_*` and `T3CODE_*` |
| Sync workflow | `timeout-minutes` 60 to 90 |
| Docs | fork-sync guide gets a Check battery section; skill names `checks[].job` |

The driver does not hard-code the job list.
It throws on a step it cannot run as an exact `vp` argv.
It skips only `sudo apt-get` and `git` provisioning lines.
There is no skip flag, and a red row blocks the push.
Note: the battery also runs the scripts suite twice, once in `fork:ci` and once in Test Scripts.

## Scope and approval

Closes #1327.
The decision comment there sets the scope: a pre-push battery and no candidate branch.

## Close conditions

- [ ] **Unmoved:** red sync leaves the trunk alone
- [ ] **Named:** the report names the red suite
- [ ] **Guard:** a test fails on an unrun CI job
- [ ] **No skip:** no flag drops a job
- [ ] **Documented:** the fork-sync guide states it

## Verification

| Condition | Test |
| --- | --- |
| Unmoved, Named | `leaves the trunk alone and names the suite when one CI test job is red` |
| Guard | `runs every hyprws CI test job before a direct trunk push` |
| No skip | `takes no flag that drops a battery row` |
| Env | `runs the battery with CI's umask and none of the live T3 instance's environment` |

<details><summary>Commands</summary>

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
vp run --filter @t3tools/scripts typecheck → exit 0
vp test run fork-sync.test.ts lib/fork-ci-jobs.test.ts fork-gate-headers.test.ts → exit 0 (56 passed)

Each derived job, umask 022, T3_* and T3CODE_* unset:
Test          → exit 0
Test Web      → exit 0
Test Scripts  → exit 0
Test Server 1 → exit 0
Test Server 2 → exit 0
Test Server 3 → exit 0
```

</details>

Claude Opus 5.5 in Claude Code.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 16, 2026
…1510)

## Problem

The hourly sync onto `v0.0.45` rebases clean, then Test Server 3 goes red on every run:

```text
FAIL src/sourceControl/GitHubCli.test.ts > GitHubCli.listPullRequestsByHead > reads heads on one repository in one GraphQL document
SchemaError: Expected a valid JSON string
```

The sync step exports `GH_REPO`, and the check battery inherits it.
Upstream's `resolveBaseRepository` (`apps/server/src/sourceControl/GitHubCli.ts:817`) returns `null` whenever `GH_REPO` is set, so the lookup falls back to `gh pr list` with no stdin, and the test's GraphQL mock fails to decode it.
Trunk has the same failure under `GH_REPO`; it only surfaced once #1499 put the server shards in the battery, and trunk reached its current base from a local sync with no `GH_REPO`.

## Change

Drop `GH_REPO` from the `Run the sync driver` env in `.github/workflows/hyprws-upstream-sync.yml`.
Every `gh` call in the driver already passes `--repo`, so the variable did nothing for it.
The comment now says why the variable must stay out.

## Scope and approval

Part of #1505. Only a clean sync run closes that issue.
Landed as a `fixup!` of 06a999c, which could not fold there: #1504 rewrote the same lines later. Reworded in place to a standalone commit.

## Verification

| Tree | Env | Command | Result |
| --- | --- | --- | --- |
| Trunk rebased onto `v0.0.45` | `GH_REPO` set | `vp test run src/sourceControl/GitHubCli.test.ts` | exit 1, same `SchemaError` |
| Trunk rebased onto `v0.0.45` | none | same | exit 0, 24 passed |
| Trunk `646fa738cd4` | `GH_REPO` set | same | exit 1, same `SchemaError` |
| Trunk `646fa738cd4` | `GH_TOKEN` only | same | exit 0, 24 passed |

<details><summary>Shard and repo checks</summary>

Rebased copy, `vp run --filter t3 test --shard 3/3`:

```diff
- GH_TOKEN + GH_REPO (old step env): exit 1, 1 failed | 142 passed | 1 skipped (144)
+ GH_TOKEN only (new step env):      exit 0, 143 passed | 1 skipped (144)
```

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
```

</details>

Claude Opus 5.5, Claude Code.

Squashes:
- ea1a440 fixup! fix(fork-sync): read hook markers at the fork tip, not the replayed blob (#1510)

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 18, 2026
…e a trunk push (#1499)

## Problem

`fork:sync` pushes the trunk after its battery, and the battery ran no `hyprws CI` test job.
A red suite reached `hyprws` on three syncs (#1327).
On the 2026-10-02 sync a green dry-run battery hid a red server suite.

## Change

| Part | Change |
| --- | --- |
| `scripts/lib/fork-ci-jobs.ts` | new: reads every `test*` job from `hyprws-ci.yml` and expands matrix cells |
| `runChecks` | runs `checkCommands`, then every derived job; red job stops at its first red step |
| Report | `CheckRow.job` names the CI job; the error lists every red one |
| Env | umask `022`; scrubs `T3_*` and `T3CODE_*` |
| Sync workflow | `timeout-minutes` 60 to 90 |
| Docs | fork-sync guide gets a Check battery section; skill names `checks[].job` |

The driver does not hard-code the job list.
It throws on a step it cannot run as an exact `vp` argv.
It skips only `sudo apt-get` and `git` provisioning lines.
There is no skip flag, and a red row blocks the push.
Note: the battery also runs the scripts suite twice, once in `fork:ci` and once in Test Scripts.

## Scope and approval

Closes #1327.
The decision comment there sets the scope: a pre-push battery and no candidate branch.

## Close conditions

- [ ] **Unmoved:** red sync leaves the trunk alone
- [ ] **Named:** the report names the red suite
- [ ] **Guard:** a test fails on an unrun CI job
- [ ] **No skip:** no flag drops a job
- [ ] **Documented:** the fork-sync guide states it

## Verification

| Condition | Test |
| --- | --- |
| Unmoved, Named | `leaves the trunk alone and names the suite when one CI test job is red` |
| Guard | `runs every hyprws CI test job before a direct trunk push` |
| No skip | `takes no flag that drops a battery row` |
| Env | `runs the battery with CI's umask and none of the live T3 instance's environment` |

<details><summary>Commands</summary>

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
vp run --filter @t3tools/scripts typecheck → exit 0
vp test run fork-sync.test.ts lib/fork-ci-jobs.test.ts fork-gate-headers.test.ts → exit 0 (56 passed)

Each derived job, umask 022, T3_* and T3CODE_* unset:
Test          → exit 0
Test Web      → exit 0
Test Scripts  → exit 0
Test Server 1 → exit 0
Test Server 2 → exit 0
Test Server 3 → exit 0
```

</details>

Claude Opus 5.5 in Claude Code.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 18, 2026
…1510)

## Problem

The hourly sync onto `v0.0.45` rebases clean, then Test Server 3 goes red on every run:

```text
FAIL src/sourceControl/GitHubCli.test.ts > GitHubCli.listPullRequestsByHead > reads heads on one repository in one GraphQL document
SchemaError: Expected a valid JSON string
```

The sync step exports `GH_REPO`, and the check battery inherits it.
Upstream's `resolveBaseRepository` (`apps/server/src/sourceControl/GitHubCli.ts:817`) returns `null` whenever `GH_REPO` is set, so the lookup falls back to `gh pr list` with no stdin, and the test's GraphQL mock fails to decode it.
Trunk has the same failure under `GH_REPO`; it only surfaced once #1499 put the server shards in the battery, and trunk reached its current base from a local sync with no `GH_REPO`.

## Change

Drop `GH_REPO` from the `Run the sync driver` env in `.github/workflows/hyprws-upstream-sync.yml`.
Every `gh` call in the driver already passes `--repo`, so the variable did nothing for it.
The comment now says why the variable must stay out.

## Scope and approval

Part of #1505. Only a clean sync run closes that issue.
Landed as a `fixup!` of 06a999c, which could not fold there: #1504 rewrote the same lines later. Reworded in place to a standalone commit.

## Verification

| Tree | Env | Command | Result |
| --- | --- | --- | --- |
| Trunk rebased onto `v0.0.45` | `GH_REPO` set | `vp test run src/sourceControl/GitHubCli.test.ts` | exit 1, same `SchemaError` |
| Trunk rebased onto `v0.0.45` | none | same | exit 0, 24 passed |
| Trunk `646fa738cd4` | `GH_REPO` set | same | exit 1, same `SchemaError` |
| Trunk `646fa738cd4` | `GH_TOKEN` only | same | exit 0, 24 passed |

<details><summary>Shard and repo checks</summary>

Rebased copy, `vp run --filter t3 test --shard 3/3`:

```diff
- GH_TOKEN + GH_REPO (old step env): exit 1, 1 failed | 142 passed | 1 skipped (144)
+ GH_TOKEN only (new step env):      exit 0, 143 passed | 1 skipped (144)
```

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
```

</details>

Claude Opus 5.5, Claude Code.

Squashes:
- ea1a440 fixup! fix(fork-sync): read hook markers at the fork tip, not the replayed blob (#1510)

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 18, 2026
…e a trunk push (#1499)

## Problem

`fork:sync` pushes the trunk after its battery, and the battery ran no `hyprws CI` test job.
A red suite reached `hyprws` on three syncs (#1327).
On the 2026-10-02 sync a green dry-run battery hid a red server suite.

## Change

| Part | Change |
| --- | --- |
| `scripts/lib/fork-ci-jobs.ts` | new: reads every `test*` job from `hyprws-ci.yml` and expands matrix cells |
| `runChecks` | runs `checkCommands`, then every derived job; red job stops at its first red step |
| Report | `CheckRow.job` names the CI job; the error lists every red one |
| Env | umask `022`; scrubs `T3_*` and `T3CODE_*` |
| Sync workflow | `timeout-minutes` 60 to 90 |
| Docs | fork-sync guide gets a Check battery section; skill names `checks[].job` |

The driver does not hard-code the job list.
It throws on a step it cannot run as an exact `vp` argv.
It skips only `sudo apt-get` and `git` provisioning lines.
There is no skip flag, and a red row blocks the push.
Note: the battery also runs the scripts suite twice, once in `fork:ci` and once in Test Scripts.

## Scope and approval

Closes #1327.
The decision comment there sets the scope: a pre-push battery and no candidate branch.

## Close conditions

- [ ] **Unmoved:** red sync leaves the trunk alone
- [ ] **Named:** the report names the red suite
- [ ] **Guard:** a test fails on an unrun CI job
- [ ] **No skip:** no flag drops a job
- [ ] **Documented:** the fork-sync guide states it

## Verification

| Condition | Test |
| --- | --- |
| Unmoved, Named | `leaves the trunk alone and names the suite when one CI test job is red` |
| Guard | `runs every hyprws CI test job before a direct trunk push` |
| No skip | `takes no flag that drops a battery row` |
| Env | `runs the battery with CI's umask and none of the live T3 instance's environment` |

<details><summary>Commands</summary>

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
vp run --filter @t3tools/scripts typecheck → exit 0
vp test run fork-sync.test.ts lib/fork-ci-jobs.test.ts fork-gate-headers.test.ts → exit 0 (56 passed)

Each derived job, umask 022, T3_* and T3CODE_* unset:
Test          → exit 0
Test Web      → exit 0
Test Scripts  → exit 0
Test Server 1 → exit 0
Test Server 2 → exit 0
Test Server 3 → exit 0
```

</details>

Claude Opus 5.5 in Claude Code.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 18, 2026
…1510)

## Problem

The hourly sync onto `v0.0.45` rebases clean, then Test Server 3 goes red on every run:

```text
FAIL src/sourceControl/GitHubCli.test.ts > GitHubCli.listPullRequestsByHead > reads heads on one repository in one GraphQL document
SchemaError: Expected a valid JSON string
```

The sync step exports `GH_REPO`, and the check battery inherits it.
Upstream's `resolveBaseRepository` (`apps/server/src/sourceControl/GitHubCli.ts:817`) returns `null` whenever `GH_REPO` is set, so the lookup falls back to `gh pr list` with no stdin, and the test's GraphQL mock fails to decode it.
Trunk has the same failure under `GH_REPO`; it only surfaced once #1499 put the server shards in the battery, and trunk reached its current base from a local sync with no `GH_REPO`.

## Change

Drop `GH_REPO` from the `Run the sync driver` env in `.github/workflows/hyprws-upstream-sync.yml`.
Every `gh` call in the driver already passes `--repo`, so the variable did nothing for it.
The comment now says why the variable must stay out.

## Scope and approval

Part of #1505. Only a clean sync run closes that issue.
Landed as a `fixup!` of 06a999c, which could not fold there: #1504 rewrote the same lines later. Reworded in place to a standalone commit.

## Verification

| Tree | Env | Command | Result |
| --- | --- | --- | --- |
| Trunk rebased onto `v0.0.45` | `GH_REPO` set | `vp test run src/sourceControl/GitHubCli.test.ts` | exit 1, same `SchemaError` |
| Trunk rebased onto `v0.0.45` | none | same | exit 0, 24 passed |
| Trunk `646fa738cd4` | `GH_REPO` set | same | exit 1, same `SchemaError` |
| Trunk `646fa738cd4` | `GH_TOKEN` only | same | exit 0, 24 passed |

<details><summary>Shard and repo checks</summary>

Rebased copy, `vp run --filter t3 test --shard 3/3`:

```diff
- GH_TOKEN + GH_REPO (old step env): exit 1, 1 failed | 142 passed | 1 skipped (144)
+ GH_TOKEN only (new step env):      exit 0, 143 passed | 1 skipped (144)
```

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
```

</details>

Claude Opus 5.5, Claude Code.

Squashes:
- ea1a440 fixup! fix(fork-sync): read hook markers at the fork tip, not the replayed blob (#1510)

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 18, 2026
…e a trunk push (#1499)

## Problem

`fork:sync` pushes the trunk after its battery, and the battery ran no `hyprws CI` test job.
A red suite reached `hyprws` on three syncs (#1327).
On the 2026-10-02 sync a green dry-run battery hid a red server suite.

## Change

| Part | Change |
| --- | --- |
| `scripts/lib/fork-ci-jobs.ts` | new: reads every `test*` job from `hyprws-ci.yml` and expands matrix cells |
| `runChecks` | runs `checkCommands`, then every derived job; red job stops at its first red step |
| Report | `CheckRow.job` names the CI job; the error lists every red one |
| Env | umask `022`; scrubs `T3_*` and `T3CODE_*` |
| Sync workflow | `timeout-minutes` 60 to 90 |
| Docs | fork-sync guide gets a Check battery section; skill names `checks[].job` |

The driver does not hard-code the job list.
It throws on a step it cannot run as an exact `vp` argv.
It skips only `sudo apt-get` and `git` provisioning lines.
There is no skip flag, and a red row blocks the push.
Note: the battery also runs the scripts suite twice, once in `fork:ci` and once in Test Scripts.

## Scope and approval

Closes #1327.
The decision comment there sets the scope: a pre-push battery and no candidate branch.

## Close conditions

- [ ] **Unmoved:** red sync leaves the trunk alone
- [ ] **Named:** the report names the red suite
- [ ] **Guard:** a test fails on an unrun CI job
- [ ] **No skip:** no flag drops a job
- [ ] **Documented:** the fork-sync guide states it

## Verification

| Condition | Test |
| --- | --- |
| Unmoved, Named | `leaves the trunk alone and names the suite when one CI test job is red` |
| Guard | `runs every hyprws CI test job before a direct trunk push` |
| No skip | `takes no flag that drops a battery row` |
| Env | `runs the battery with CI's umask and none of the live T3 instance's environment` |

<details><summary>Commands</summary>

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
vp run --filter @t3tools/scripts typecheck → exit 0
vp test run fork-sync.test.ts lib/fork-ci-jobs.test.ts fork-gate-headers.test.ts → exit 0 (56 passed)

Each derived job, umask 022, T3_* and T3CODE_* unset:
Test          → exit 0
Test Web      → exit 0
Test Scripts  → exit 0
Test Server 1 → exit 0
Test Server 2 → exit 0
Test Server 3 → exit 0
```

</details>

Claude Opus 5.5 in Claude Code.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 18, 2026
…1510)

## Problem

The hourly sync onto `v0.0.45` rebases clean, then Test Server 3 goes red on every run:

```text
FAIL src/sourceControl/GitHubCli.test.ts > GitHubCli.listPullRequestsByHead > reads heads on one repository in one GraphQL document
SchemaError: Expected a valid JSON string
```

The sync step exports `GH_REPO`, and the check battery inherits it.
Upstream's `resolveBaseRepository` (`apps/server/src/sourceControl/GitHubCli.ts:817`) returns `null` whenever `GH_REPO` is set, so the lookup falls back to `gh pr list` with no stdin, and the test's GraphQL mock fails to decode it.
Trunk has the same failure under `GH_REPO`; it only surfaced once #1499 put the server shards in the battery, and trunk reached its current base from a local sync with no `GH_REPO`.

## Change

Drop `GH_REPO` from the `Run the sync driver` env in `.github/workflows/hyprws-upstream-sync.yml`.
Every `gh` call in the driver already passes `--repo`, so the variable did nothing for it.
The comment now says why the variable must stay out.

## Scope and approval

Part of #1505. Only a clean sync run closes that issue.
Landed as a `fixup!` of 06a999c, which could not fold there: #1504 rewrote the same lines later. Reworded in place to a standalone commit.

## Verification

| Tree | Env | Command | Result |
| --- | --- | --- | --- |
| Trunk rebased onto `v0.0.45` | `GH_REPO` set | `vp test run src/sourceControl/GitHubCli.test.ts` | exit 1, same `SchemaError` |
| Trunk rebased onto `v0.0.45` | none | same | exit 0, 24 passed |
| Trunk `646fa738cd4` | `GH_REPO` set | same | exit 1, same `SchemaError` |
| Trunk `646fa738cd4` | `GH_TOKEN` only | same | exit 0, 24 passed |

<details><summary>Shard and repo checks</summary>

Rebased copy, `vp run --filter t3 test --shard 3/3`:

```diff
- GH_TOKEN + GH_REPO (old step env): exit 1, 1 failed | 142 passed | 1 skipped (144)
+ GH_TOKEN only (new step env):      exit 0, 143 passed | 1 skipped (144)
```

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
```

</details>

Claude Opus 5.5, Claude Code.

Squashes:
- ea1a440 fixup! fix(fork-sync): read hook markers at the fork tip, not the replayed blob (#1510)

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 19, 2026
…e a trunk push (#1499)

## Problem

`fork:sync` pushes the trunk after its battery, and the battery ran no `hyprws CI` test job.
A red suite reached `hyprws` on three syncs (#1327).
On the 2026-10-02 sync a green dry-run battery hid a red server suite.

## Change

| Part | Change |
| --- | --- |
| `scripts/lib/fork-ci-jobs.ts` | new: reads every `test*` job from `hyprws-ci.yml` and expands matrix cells |
| `runChecks` | runs `checkCommands`, then every derived job; red job stops at its first red step |
| Report | `CheckRow.job` names the CI job; the error lists every red one |
| Env | umask `022`; scrubs `T3_*` and `T3CODE_*` |
| Sync workflow | `timeout-minutes` 60 to 90 |
| Docs | fork-sync guide gets a Check battery section; skill names `checks[].job` |

The driver does not hard-code the job list.
It throws on a step it cannot run as an exact `vp` argv.
It skips only `sudo apt-get` and `git` provisioning lines.
There is no skip flag, and a red row blocks the push.
Note: the battery also runs the scripts suite twice, once in `fork:ci` and once in Test Scripts.

## Scope and approval

Closes #1327.
The decision comment there sets the scope: a pre-push battery and no candidate branch.

## Close conditions

- [ ] **Unmoved:** red sync leaves the trunk alone
- [ ] **Named:** the report names the red suite
- [ ] **Guard:** a test fails on an unrun CI job
- [ ] **No skip:** no flag drops a job
- [ ] **Documented:** the fork-sync guide states it

## Verification

| Condition | Test |
| --- | --- |
| Unmoved, Named | `leaves the trunk alone and names the suite when one CI test job is red` |
| Guard | `runs every hyprws CI test job before a direct trunk push` |
| No skip | `takes no flag that drops a battery row` |
| Env | `runs the battery with CI's umask and none of the live T3 instance's environment` |

<details><summary>Commands</summary>

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
vp run --filter @t3tools/scripts typecheck → exit 0
vp test run fork-sync.test.ts lib/fork-ci-jobs.test.ts fork-gate-headers.test.ts → exit 0 (56 passed)

Each derived job, umask 022, T3_* and T3CODE_* unset:
Test          → exit 0
Test Web      → exit 0
Test Scripts  → exit 0
Test Server 1 → exit 0
Test Server 2 → exit 0
Test Server 3 → exit 0
```

</details>

Claude Opus 5.5 in Claude Code.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 19, 2026
…1510)

## Problem

The hourly sync onto `v0.0.45` rebases clean, then Test Server 3 goes red on every run:

```text
FAIL src/sourceControl/GitHubCli.test.ts > GitHubCli.listPullRequestsByHead > reads heads on one repository in one GraphQL document
SchemaError: Expected a valid JSON string
```

The sync step exports `GH_REPO`, and the check battery inherits it.
Upstream's `resolveBaseRepository` (`apps/server/src/sourceControl/GitHubCli.ts:817`) returns `null` whenever `GH_REPO` is set, so the lookup falls back to `gh pr list` with no stdin, and the test's GraphQL mock fails to decode it.
Trunk has the same failure under `GH_REPO`; it only surfaced once #1499 put the server shards in the battery, and trunk reached its current base from a local sync with no `GH_REPO`.

## Change

Drop `GH_REPO` from the `Run the sync driver` env in `.github/workflows/hyprws-upstream-sync.yml`.
Every `gh` call in the driver already passes `--repo`, so the variable did nothing for it.
The comment now says why the variable must stay out.

## Scope and approval

Part of #1505. Only a clean sync run closes that issue.
Landed as a `fixup!` of 06a999c, which could not fold there: #1504 rewrote the same lines later. Reworded in place to a standalone commit.

## Verification

| Tree | Env | Command | Result |
| --- | --- | --- | --- |
| Trunk rebased onto `v0.0.45` | `GH_REPO` set | `vp test run src/sourceControl/GitHubCli.test.ts` | exit 1, same `SchemaError` |
| Trunk rebased onto `v0.0.45` | none | same | exit 0, 24 passed |
| Trunk `646fa738cd4` | `GH_REPO` set | same | exit 1, same `SchemaError` |
| Trunk `646fa738cd4` | `GH_TOKEN` only | same | exit 0, 24 passed |

<details><summary>Shard and repo checks</summary>

Rebased copy, `vp run --filter t3 test --shard 3/3`:

```diff
- GH_TOKEN + GH_REPO (old step env): exit 1, 1 failed | 142 passed | 1 skipped (144)
+ GH_TOKEN only (new step env):      exit 0, 143 passed | 1 skipped (144)
```

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
```

</details>

Claude Opus 5.5, Claude Code.

Squashes:
- ea1a440 fixup! fix(fork-sync): read hook markers at the fork tip, not the replayed blob (#1510)

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 19, 2026
…e a trunk push (#1499)

## Problem

`fork:sync` pushes the trunk after its battery, and the battery ran no `hyprws CI` test job.
A red suite reached `hyprws` on three syncs (#1327).
On the 2026-10-02 sync a green dry-run battery hid a red server suite.

## Change

| Part | Change |
| --- | --- |
| `scripts/lib/fork-ci-jobs.ts` | new: reads every `test*` job from `hyprws-ci.yml` and expands matrix cells |
| `runChecks` | runs `checkCommands`, then every derived job; red job stops at its first red step |
| Report | `CheckRow.job` names the CI job; the error lists every red one |
| Env | umask `022`; scrubs `T3_*` and `T3CODE_*` |
| Sync workflow | `timeout-minutes` 60 to 90 |
| Docs | fork-sync guide gets a Check battery section; skill names `checks[].job` |

The driver does not hard-code the job list.
It throws on a step it cannot run as an exact `vp` argv.
It skips only `sudo apt-get` and `git` provisioning lines.
There is no skip flag, and a red row blocks the push.
Note: the battery also runs the scripts suite twice, once in `fork:ci` and once in Test Scripts.

## Scope and approval

Closes #1327.
The decision comment there sets the scope: a pre-push battery and no candidate branch.

## Close conditions

- [ ] **Unmoved:** red sync leaves the trunk alone
- [ ] **Named:** the report names the red suite
- [ ] **Guard:** a test fails on an unrun CI job
- [ ] **No skip:** no flag drops a job
- [ ] **Documented:** the fork-sync guide states it

## Verification

| Condition | Test |
| --- | --- |
| Unmoved, Named | `leaves the trunk alone and names the suite when one CI test job is red` |
| Guard | `runs every hyprws CI test job before a direct trunk push` |
| No skip | `takes no flag that drops a battery row` |
| Env | `runs the battery with CI's umask and none of the live T3 instance's environment` |

<details><summary>Commands</summary>

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
vp run --filter @t3tools/scripts typecheck → exit 0
vp test run fork-sync.test.ts lib/fork-ci-jobs.test.ts fork-gate-headers.test.ts → exit 0 (56 passed)

Each derived job, umask 022, T3_* and T3CODE_* unset:
Test          → exit 0
Test Web      → exit 0
Test Scripts  → exit 0
Test Server 1 → exit 0
Test Server 2 → exit 0
Test Server 3 → exit 0
```

</details>

Claude Opus 5.5 in Claude Code.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 19, 2026
…1510)

## Problem

The hourly sync onto `v0.0.45` rebases clean, then Test Server 3 goes red on every run:

```text
FAIL src/sourceControl/GitHubCli.test.ts > GitHubCli.listPullRequestsByHead > reads heads on one repository in one GraphQL document
SchemaError: Expected a valid JSON string
```

The sync step exports `GH_REPO`, and the check battery inherits it.
Upstream's `resolveBaseRepository` (`apps/server/src/sourceControl/GitHubCli.ts:817`) returns `null` whenever `GH_REPO` is set, so the lookup falls back to `gh pr list` with no stdin, and the test's GraphQL mock fails to decode it.
Trunk has the same failure under `GH_REPO`; it only surfaced once #1499 put the server shards in the battery, and trunk reached its current base from a local sync with no `GH_REPO`.

## Change

Drop `GH_REPO` from the `Run the sync driver` env in `.github/workflows/hyprws-upstream-sync.yml`.
Every `gh` call in the driver already passes `--repo`, so the variable did nothing for it.
The comment now says why the variable must stay out.

## Scope and approval

Part of #1505. Only a clean sync run closes that issue.
Landed as a `fixup!` of 06a999c, which could not fold there: #1504 rewrote the same lines later. Reworded in place to a standalone commit.

## Verification

| Tree | Env | Command | Result |
| --- | --- | --- | --- |
| Trunk rebased onto `v0.0.45` | `GH_REPO` set | `vp test run src/sourceControl/GitHubCli.test.ts` | exit 1, same `SchemaError` |
| Trunk rebased onto `v0.0.45` | none | same | exit 0, 24 passed |
| Trunk `646fa738cd4` | `GH_REPO` set | same | exit 1, same `SchemaError` |
| Trunk `646fa738cd4` | `GH_TOKEN` only | same | exit 0, 24 passed |

<details><summary>Shard and repo checks</summary>

Rebased copy, `vp run --filter t3 test --shard 3/3`:

```diff
- GH_TOKEN + GH_REPO (old step env): exit 1, 1 failed | 142 passed | 1 skipped (144)
+ GH_TOKEN only (new step env):      exit 0, 143 passed | 1 skipped (144)
```

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
```

</details>

Claude Opus 5.5, Claude Code.

Squashes:
- ea1a440 fixup! fix(fork-sync): read hook markers at the fork tip, not the replayed blob (#1510)

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 19, 2026
…e a trunk push (#1499)

## Problem

`fork:sync` pushes the trunk after its battery, and the battery ran no `hyprws CI` test job.
A red suite reached `hyprws` on three syncs (#1327).
On the 2026-10-02 sync a green dry-run battery hid a red server suite.

## Change

| Part | Change |
| --- | --- |
| `scripts/lib/fork-ci-jobs.ts` | new: reads every `test*` job from `hyprws-ci.yml` and expands matrix cells |
| `runChecks` | runs `checkCommands`, then every derived job; red job stops at its first red step |
| Report | `CheckRow.job` names the CI job; the error lists every red one |
| Env | umask `022`; scrubs `T3_*` and `T3CODE_*` |
| Sync workflow | `timeout-minutes` 60 to 90 |
| Docs | fork-sync guide gets a Check battery section; skill names `checks[].job` |

The driver does not hard-code the job list.
It throws on a step it cannot run as an exact `vp` argv.
It skips only `sudo apt-get` and `git` provisioning lines.
There is no skip flag, and a red row blocks the push.
Note: the battery also runs the scripts suite twice, once in `fork:ci` and once in Test Scripts.

## Scope and approval

Closes #1327.
The decision comment there sets the scope: a pre-push battery and no candidate branch.

## Close conditions

- [ ] **Unmoved:** red sync leaves the trunk alone
- [ ] **Named:** the report names the red suite
- [ ] **Guard:** a test fails on an unrun CI job
- [ ] **No skip:** no flag drops a job
- [ ] **Documented:** the fork-sync guide states it

## Verification

| Condition | Test |
| --- | --- |
| Unmoved, Named | `leaves the trunk alone and names the suite when one CI test job is red` |
| Guard | `runs every hyprws CI test job before a direct trunk push` |
| No skip | `takes no flag that drops a battery row` |
| Env | `runs the battery with CI's umask and none of the live T3 instance's environment` |

<details><summary>Commands</summary>

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
vp run --filter @t3tools/scripts typecheck → exit 0
vp test run fork-sync.test.ts lib/fork-ci-jobs.test.ts fork-gate-headers.test.ts → exit 0 (56 passed)

Each derived job, umask 022, T3_* and T3CODE_* unset:
Test          → exit 0
Test Web      → exit 0
Test Scripts  → exit 0
Test Server 1 → exit 0
Test Server 2 → exit 0
Test Server 3 → exit 0
```

</details>

Claude Opus 5.5 in Claude Code.

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
donjor added a commit that referenced this pull request Oct 19, 2026
…1510)

## Problem

The hourly sync onto `v0.0.45` rebases clean, then Test Server 3 goes red on every run:

```text
FAIL src/sourceControl/GitHubCli.test.ts > GitHubCli.listPullRequestsByHead > reads heads on one repository in one GraphQL document
SchemaError: Expected a valid JSON string
```

The sync step exports `GH_REPO`, and the check battery inherits it.
Upstream's `resolveBaseRepository` (`apps/server/src/sourceControl/GitHubCli.ts:817`) returns `null` whenever `GH_REPO` is set, so the lookup falls back to `gh pr list` with no stdin, and the test's GraphQL mock fails to decode it.
Trunk has the same failure under `GH_REPO`; it only surfaced once #1499 put the server shards in the battery, and trunk reached its current base from a local sync with no `GH_REPO`.

## Change

Drop `GH_REPO` from the `Run the sync driver` env in `.github/workflows/hyprws-upstream-sync.yml`.
Every `gh` call in the driver already passes `--repo`, so the variable did nothing for it.
The comment now says why the variable must stay out.

## Scope and approval

Part of #1505. Only a clean sync run closes that issue.
Landed as a `fixup!` of 06a999c, which could not fold there: #1504 rewrote the same lines later. Reworded in place to a standalone commit.

## Verification

| Tree | Env | Command | Result |
| --- | --- | --- | --- |
| Trunk rebased onto `v0.0.45` | `GH_REPO` set | `vp test run src/sourceControl/GitHubCli.test.ts` | exit 1, same `SchemaError` |
| Trunk rebased onto `v0.0.45` | none | same | exit 0, 24 passed |
| Trunk `646fa738cd4` | `GH_REPO` set | same | exit 1, same `SchemaError` |
| Trunk `646fa738cd4` | `GH_TOKEN` only | same | exit 0, 24 passed |

<details><summary>Shard and repo checks</summary>

Rebased copy, `vp run --filter t3 test --shard 3/3`:

```diff
- GH_TOKEN + GH_REPO (old step env): exit 1, 1 failed | 142 passed | 1 skipped (144)
+ GH_TOKEN only (new step env):      exit 0, 143 passed | 1 skipped (144)
```

```text
vp run fork:ci → exit 0
vp run fork:delta --check → exit 0
```

</details>

Claude Opus 5.5, Claude Code.

Squashes:
- ea1a440 fixup! fix(fork-sync): read hook markers at the fork tip, not the replayed blob (#1510)

## Fork trailers

Fork-Domain: fork-meta
Fork-Tier: core
Fork-Upstreamable: no
Co-authored-by: donjor <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fork sync runs the app test suites before it pushes [✨#1325]

1 participant