Skip to content

ci: run every cross-version wire test, picked up by folder so new ones can't be skipped - #24499

Merged
brennanb2025 merged 7 commits into
mainfrom
brennanb2025/xv-tests-run-in-ci
Oct 2, 2026
Merged

brennanb2025 merged 7 commits into
mainfrom
brennanb2025/xv-tests-run-in-ci

Conversation

@brennanb2025

@brennanb2025 brennanb2025 commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 3 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​113 $\color{#cf222e}{\Huge{\mathbf{−}}}$​2 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​111
Prod 3 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​23 $\color{#cf222e}{\Huge{\mathbf{−}}}$​16 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​7

ELI5

Orca has "cross-version" tests: they load an older Orca release next to the current code and check the two still work together, because a phone, a desktop and a remote server update at different times. Three of these tests were never run by CI. They passed or failed with nobody watching, so they protected nothing. This PR makes CI run every test in that folder, including ones added later, and adds a check that fails if a test is ever left out again.

What Changed

The problem. The cross-version wire compatibility job in .github/workflows/pr.yml ran a list of test files typed out by hand. The main unit test job skips that whole folder on purpose: these tests need the full git history to find old releases, and the main job checks out without it. So a file in the folder ran only if someone remembered to add it to the list. Three files were never added:

  • cross-version-host-observed-turn-end.unit.test.ts
  • orchestration-delivery-downgrade.unit.test.ts
  • published-field-shape.unit.test.ts

Nothing reported this. CI stayed green whether these tests passed or not.

The fix.

  1. The job now runs the folder, tests/e2e/cross-version-wire/, instead of a list. A new test file there runs in CI as soon as it is added, with no list to update. If the folder ever matches no tests, vitest exits with an error, so the job still cannot pass while running nothing.

  2. A new check, config/scripts/ci-unit-exclusion-coverage.test.mjs, runs with the normal unit tests. It finds every test file the main unit job deliberately skips and fails unless:

    • a job that can block a merge runs it. Jobs left out of the final verify gate (e2e, real IME, real WSL terminal) don't count, because they can be red or skipped without stopping a merge.
    • a PR that edits only that file starts that job. Each job only starts for certain paths, so a test that is run by a job its own edits don't start is effectively unguarded.

    This covers this folder and every other skipped file, such as the real-shell tests and the relay-region tests. It also fails if a test in the folder is named so that vitest would not pick it up (anything not ending in .unit.test.ts).

  3. The cross-version job only starts when a PR touches certain paths, and that path list is also kept by hand. I added the modules the two newly running release tests check, so a change to that code now starts the job: the agent status and turn-outcome modules for the turn-end test, and the orchestration database and its schema-version handling for the downgrade test.

  4. The second rule in step 2 found one more test that already ran nowhere when edited: src/main/runtime/structured-session-cli-login-shell.live-shell.test.ts runs only in the shell contracts job, but a change to it, its test harness, or the module it tests (structured-session-child-identity-env) didn't start that job. Those three paths now do.

Nothing changes in the app. Only CI is affected.

What each newly running test checks

  • Host-observed turn end: a new host can report that a turn ended in a crash (interruption), that it could not confirm the end (unconfirmed), or that a newer request replaced it (superseded). An older desktop reading those values must keep the row and show it as done, not drop it or treat it as a user stop. Covers live status, sleeping-agent records and journal turns.
  • Orchestration delivery downgrade: a database written by current code can be opened by an older build (before schema version 41). The old build acknowledges and writes messages, and current code then reopens the database without losing or replaying a delivery.
  • Published field shape: the helper the terminal cross-version test uses to compare the fields each side sends. It catches a field that one side stopped sending, and it refuses to compare lists of different lengths instead of quietly cutting them short.

Why

Running the folder takes the hand-kept list out of the loop entirely. The alternative was to keep the list and add a check that it matches the folder. That still makes every author edit the workflow, and it is the step that was already forgotten three times. The coverage check goes further than this folder because the real bug is general: any file the main unit job skips must run somewhere, and before this nothing checked that.

Testing

  • Ran the coverage check against the old workflow. It failed and listed exactly the three files above. It passes with the new workflow.
  • Ran the related CI script tests: pr-code-change-scope, pr-workflow-parallelism, ci-unit-plan and ci-unit-selection.
  • Each rule of the coverage check fails when its fix is taken out: listing a file that only the e2e job runs as skipped fails the merge-blocking rule, and removing the new shell or cross-version paths fails the matching rule or classification test.
  • CI on this branch: the cross-version job ran all 13 files, 82/82 tests, in about 58 s.
  • vitest list --config config/vitest.config.ts tests/e2e/cross-version-wire/ selects all 13 test files in the folder: the 10 the list named plus the 3 above.
  • Ran the three newly included files locally with the CI command (vitest run --config config/vitest.config.ts <file>), on a heavily loaded Mac:
    • published-field-shape: 8/8 pass.
    • cross-version-host-observed-turn-end: 5/5 pass.
    • orchestration-delivery-downgrade: passes (1/1) once the old release is unpacked. The first run on this machine hit the 30-second test timeout while unpacking that release, so I passed a longer --testTimeout to get one clean run. With the release already unpacked, the test takes about 3 seconds. In CI, tests built the same way unpack their release in 6 to 14 seconds.

Notes

  • Timing: orchestration-delivery-downgrade unpacks an old release inside its test body. That unpacking has its own 45 s deadline, which alone is longer than vitest's 30 s default test timeout, so the test now has a 120 s budget. In CI the file took about 8 s cold. No assertion changed. Running the three extra files adds about 5 to 10 s to the cross-version job (now about 58 s for its test step, 13 files, 82 tests).
  • Not changed (deliberately): the paths that start the cross-version job are still a hand-kept list in config/scripts/pr-code-change-scope.mjs. Deriving them from the import graph isn't a clear win: the path-detection job checks out only a handful of files and installs no dependencies, and the full import closure of these tests is around 3,000 source files, so a graph-based trigger would start the job on most PRs. Some modules existing tests check are still not on the list (for example the session-tab retirement proof and the worktree identity migration); adding those is a separate change.

…est is left out

Three cross-version tests ran in no CI job because the job named its files by hand.
Run the directory instead, ratchet that every file kept out of the unit shards
runs in some PR job, and re-run the job when the modules the newly running
tests guard change.
@greptile-apps

greptile-apps Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 5/5

[Medium risk] Changes how cross-version compatibility tests are discovered and run.

The PR appears safe to merge; no new actionable issue was established.

Summary

The PR replaces a hand-maintained cross-version test list with directory selection, adds a check that excluded unit tests are covered by gating jobs, expands relevant path triggers, and increases the timeout for a release-checkout test.

Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart LR
  A[PR path classification] --> B[Cross-version wire job]
  B --> C[Run cross-version-wire directory]
  A --> D[Sharded unit job]
  D --> E[Check excluded-test coverage]
Loading

Reviews (3) · Last reviewed commit: "test(ci): glob the unit tree once for th..."

Comment thread config/scripts/ci-unit-exclusion-coverage.test.mjs Outdated
@coderabbitai

coderabbitai Bot commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Advanced

Run ID: fa40b71a-87b3-4f8b-a3a6-1b1eaf0fdf3f

📥 Commits

Reviewing files that changed from the base of the PR and between 88e0a23 and 1e5e9a7.

📒 Files selected for processing (1)
  • config/scripts/ci-unit-exclusion-coverage.test.mjs

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 6 remain after this review.


📝 Walkthrough

Walkthrough

The cross-version wire job now runs Vitest against the full test directory. New CI tests check that excluded unit tests are covered by PR Vitest steps and that the directory’s tests match UNIT_INCLUDE. Additional source path prefixes route selected changes to the cross-version wire job. The orchestration downgrade test now has a 120-second timeout.

Priority: ⬇️ Low

Merge Risk: ⚪ Minimal · up to 1e5e9

The PR broadens CI test coverage, and the previously reported shell-test routing gap is addressed at the reviewed head. No unresolved current impact prevents merging, subject to normal CI checks.

Security Architecture Review

Security architecture risk: 🔵 Low · up to 1e5e9

The change broadens test coverage without showing additional repository-write permissions or production access. No introduced security concern was established. Complete dependency-to-job coverage and externally enforced cache and cancellation behavior remain unverified.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — Directory-wide selection increases the PR-authored test code reached by this CI job. The demonstrated exposure is the job runner, checked-out source and existing dependency-cache paths; the inspected change does not establish new tenant, production-data or repository-write authority.

Trust Boundaries and Controls

  • observed — The new coverage test treats workflow commands as text for extracting paths, not as executable instructions. The executing cross-version job retains read-only repository permissions and checkout credential persistence disabled.

Resilience and Maintainability Implications

  • inferred — Unique temporary database ownership and runner-local release-checkout state contain ordinary test failures. Checkout stamp validation, locking and stale-staging scavenging support repetition and recovery. Hard cancellation may bypass finally cleanup; repository source alone does not establish runner teardown guarantees.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 6 functions across 5 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly identifies the main change: running every cross-version wire test by directory so new tests are not omitted. It is specific and relevant.
Description check ✅ Passed The description is mostly complete. It explains the problem, changes, rationale, and testing in detail. It omits the Linked Issue section and the required Visual Proof statement of “N/A” with a reason…
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Advanced

Run ID: e4b2e907-d967-4b1a-bedd-ffb9ce40842d

📥 Commits

Reviewing files that changed from the base of the PR and between 4534087 and 7bb4271.

📒 Files selected for processing (6)
  • .github/workflows/pr.yml
  • config/scripts/ci-unit-exclusion-coverage.test.mjs
  • config/scripts/ci-unit-files.mjs
  • config/scripts/pr-code-change-scope.mjs
  • config/scripts/pr-code-change-scope.test.mjs
  • tests/e2e/cross-version-wire/orchestration-delivery-downgrade.unit.test.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 4 remain after this review.

Comment on lines +41 to +56
describe('unit files kept out of the sharded test job', () => {
it('each still runs in some PR job', () => {
const sharded = new Set(discoverUnitFiles())
const excluded = posixPaths(globSync(UNIT_INCLUDE, { exclude: defaultExclude })).filter(
(file) => !sharded.has(file)
)
const pathArguments = vitestPathArguments()

expect(excluded.length).toBeGreaterThan(0)
// Why: an excluded file no step names guards nothing, and nothing else reports it.
expect(excluded.filter((file) => !runByPrVitestStep(file, pathArguments))).toEqual([])
})

it('runs the whole cross-version-wire directory, not a list of its files', () => {
expect(vitestPathArguments()).toContain(CROSS_VERSION_WIRE_DIR)
})

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🔎 Supported by static analysis

🏁 Script executed:

sed -n '1,105p' config/scripts/ci-unit-exclusion-coverage.test.mjs
sed -n '1,95p' config/scripts/ci-unit-files.mjs

Repository: stablyai/orca

Length of output: 4838


🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- workflow files ---'
find .github/workflows -maxdepth 1 -type f -print | sort
printf '%s\n' '--- pr.yml ---'
cat -n .github/workflows/pr.yml
printf '%s\n' '--- locally called workflows referenced by pr.yml ---'
rg -n -C 3 'uses:\s*\./\.github/workflows/' .github/workflows/pr.yml
for f in $(rg -o 'uses:\s*\./\.github/workflows/[^[:space:]]+' .github/workflows/pr.yml | sed 's/^uses:[[:space:]]*//' | sort -u); do
  printf '%s\n' "--- ${f#./} ---"
  cat -n "${f#./}"
done
printf '%s\n' '--- vitest invocations and conditions across workflows ---'
rg -n -C 4 'vitest|^\s*(if|paths|paths-ignore|on):' .github/workflows

Repository: stablyai/orca

Length of output: 45665


🏁 Script executed:

set -eu
find .github/workflows -maxdepth 1 -type f -print | sort
printf '%s\n' '--- pr.yml ---'
cat -n .github/workflows/pr.yml
printf '%s\n' '--- locally called workflows ---'
rg -n -o 'uses:\s*\./\.github/workflows/[^\s]+' .github/workflows/pr.yml | sed 's/.*uses:[[:space:]]*//' | sort -u | while read -r path; do
  printf '%s\n' "--- ${path#./} ---"
  cat -n "${path#./}"
done
printf '%s\n' '--- workflow Vitest and condition context ---'
rg -n -C 4 'vitest|^\s*(if|paths|paths-ignore|on):' .github/workflows

Repository: stablyai/orca

Length of output: 45665


🏁 Script executed:

set -eu
find .github/workflows -maxdepth 1 -type f -print | sort
cat -n .github/workflows/pr.yml
rg -n -C 5 'uses:\s*\./\.github/workflows/|vitest|^\s*(if|paths|paths-ignore|on):' .github/workflows

Repository: stablyai/orca

Length of output: 45595


🏁 Script executed:

set -eu
printf '%s\n' '--- pr.yml relevant structure ---'
rg -n -C 3 'uses: \./\.github/workflows/|vitest|^\s{2}[A-Za-z0-9_.-]+:|^\s{4}if:|^\s{6}- name:' .github/workflows/pr.yml
printf '%s\n' '--- exact local workflow references ---'
rg -n 'uses: \./\.github/workflows/' .github/workflows/pr.yml
printf '%s\n' '--- Vitest commands in pr.yml and likely called workflows ---'
for f in .github/workflows/pr.yml .github/workflows/unit-tests.yml .github/workflows/unit-plan.yml .github/workflows/unit-selection-evidence.yml .github/workflows/pr-test-loc.yml; do
  if test -f "$f"; then
    printf '%s\n' "--- $f ---"
    rg -n -C 8 'vitest|^\s{4}if:|^\s{2}[A-Za-z0-9_.-]+:|uses: \./\.github/workflows/' "$f"
  fi
done

Repository: stablyai/orca

Length of output: 42578


🏁 Script executed:

set -eu
rg -n -C 3 'uses: \./\.github/workflows/|vitest|^\s{4}if:|^\s{2}[A-Za-z0-9_.-]+:' .github/workflows/pr.yml
rg -n 'uses: \./\.github/workflows/' .github/workflows/pr.yml
for f in .github/workflows/pr.yml .github/workflows/unit-tests.yml .github/workflows/unit-plan.yml .github/workflows/unit-selection-evidence.yml .github/workflows/pr-test-loc.yml; do
  if test -f "$f"; then
    printf '%s\n' "--- $f ---"
    rg -n -C 8 'vitest|^\s{4}if:|^\s{2}[A-Za-z0-9_.-]+:|uses: \./\.github/workflows/' "$f"
  fi
done

Repository: stablyai/orca

Length of output: 44429


🏁 Script executed:

set -eu
printf '%s\n' '--- classifier outline and relevant rules ---'
rg -n -C 8 'shell_contracts|cross-version-wire|test|package|git_compatibility|function|export|return|src/main/daemon|node-pty|live-shell|shell-ready' config/scripts/pr-code-change-scope.mjs
printf '%s\n' '--- complete current exclusion and discovery declarations ---'
cat -n config/scripts/ci-unit-files.mjs
printf '%s\n' '--- current diff for the changed assertion and related CI files ---'
git diff --stat 757736628f0dc0dfa972350b22524df0ca9d6f62d5 7bb42714a20e5e1c7a5264e4f140d9076a8e62d5 -- config/scripts/ci-unit-exclusion-coverage.test.mjs config/scripts/ci-unit-files.mjs .github/workflows/pr.yml config/scripts/pr-code-change-scope.mjs

Repository: stablyai/orca

Length of output: 22555


🏁 Script executed:

set -eu
rg -n -C 8 'shell_contracts|cross-version-wire|test|package|git_compatibility|src/main/daemon|node-pty|live-shell|shell-ready' config/scripts/pr-code-change-scope.mjs
cat -n config/scripts/ci-unit-files.mjs
git diff --stat 757736628f0dc0dfa972350b22524df0ca9d6f62d5 7bb42714a20e5e1c7a5264e4f140d9076a8e62d5 -- config/scripts/ci-unit-exclusion-coverage.test.mjs config/scripts/ci-unit-files.mjs .github/workflows/pr.yml config/scripts/pr-code-change-scope.mjs

Repository: stablyai/orca

Length of output: 17294


🏁 Script executed:

set -eu
target='src/main/runtime/structured-session-cli-login-shell.live-shell.test.ts'
printf '%s\n' '--- exact path references in PR workflows and configs ---'
rg -n -C 4 -F "$target" .github/workflows config/scripts config/vitest.config.ts package.json
printf '%s\n' '--- Vitest config and unit exclusion references ---'
rg -n -C 8 'UNIT_EXCLUDE|unit-files|defaultExclude|exclude:|include:|structured-session|live-shell|vitest' config/vitest.config.ts config/scripts package.json
printf '%s\n' '--- classifier shell detector and changed-path behavior ---'
sed -n '80,110p' config/scripts/pr-code-change-scope.mjs
sed -n '418,472p' config/scripts/pr-code-change-scope.mjs

Repository: stablyai/orca

Length of output: 45663


🏁 Script executed:

set -eu
target='src/main/runtime/structured-session-cli-login-shell.live-shell.test.ts'
rg -n -C 4 -F "$target" .github/workflows config/scripts config/vitest.config.ts package.json
rg -n -C 8 'UNIT_EXCLUDE|unit-files|defaultExclude|exclude:|include:|structured-session|live-shell|vitest' config/vitest.config.ts config/scripts package.json
sed -n '80,110p' config/scripts/pr-code-change-scope.mjs
sed -n '418,472p' config/scripts/pr-code-change-scope.mjs

Repository: stablyai/orca

Length of output: 45655


Route the structured-session shell test to shell_contracts.

src/main/runtime/structured-session-cli-login-shell.live-shell.test.ts is excluded from the sharded unit job and listed in the shell Vitest command. However, its path matches no SHELL_PREFIXES entry. A PR that changes only this test therefore skips shell_contracts. The new assertion still passes because it checks the textual Vitest path, while the test runs in no PR Vitest job.

Suggested fix
   'src/main/terminal-history-fish',
   'src/main/zsh-',
+  'src/main/runtime/structured-session-cli-login-shell',
   'src/renderer/src/components/terminal-pane/fish-color-scheme',

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ Minor suggestions only.

Reviewed changes

  • Cross-version job runs the folder: .github/workflows/pr.yml now passes tests/e2e/cross-version-wire/ to vitest instead of a hand-typed list, so a new *.unit.test.ts there runs with no workflow edit; an empty match still exits non-zero.
  • One folder constant: ci-unit-files.mjs exports CROSS_VERSION_WIRE_DIR and reuses it in UNIT_EXCLUDE, so the exclude pattern and the workflow argument share a source.
  • New coverage guard: ci-unit-exclusion-coverage.test.mjs parses pr.yml plus its directly-called reusable workflows and fails when a unit file the sharded job excludes is named by no PR vitest step, when the directory argument is absent, or when a cross-version test is named so UNIT_INCLUDE misses it.
  • Trigger expansion: pr-code-change-scope.mjs adds the agent-status/turn modules and orchestration DB paths so the newly-running release tests start the job on their production dependencies.
  • Timeout budget: orchestration-delivery-downgrade.unit.test.ts moves from the 30 s default to 120_000, matching its downgrade siblings.

I verified the central claim independently: vitest list --config config/vitest.config.ts tests/e2e/cross-version-wire/ selects all 13 *.unit.test.ts files (including the 3 previously unlisted), the new guard passes on this head, all added prefix entries map to real files, and every extra UNIT_EXCLUDE entry is named by a PR vitest step.

Technical details
# Guard models Vitest's positional args more strictly than Vitest does

## Affected sites
- `config/scripts/ci-unit-exclusion-coverage.test.mjs:37` — `path === file || (path.endsWith('/') && file.startsWith(path))`.

## Required outcome
- The coverage guard should consider a file run when Vitest would run it. Today it only accepts an exact file path or a root-anchored directory prefix, while Vitest matches positional arguments as substrings.

## Suggested approach (optional)
- `pathArguments.some((path) => file.includes(path))` mirrors Vitest for both the file and directory forms.

## Open questions for the human (optional)
- If the intent is deliberately to accept only root-anchored paths, a one-line comment saying so would make the stricter contract explicit.

Pullfrog  | Fix all ➔ | Fix 👍s ➔ | View workflow run | Using deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏


function runByPrVitestStep(file, pathArguments) {
return pathArguments.some(
(path) => path === file || (path.endsWith('/') && file.startsWith(path))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This treats a directory argument as a root-anchored prefix (file.startsWith(path)), but Vitest matches positional arguments as substrings — confirmed in this repo: vitest list --config config/vitest.config.ts cross-version-wire/ selects the same files, and the pr.yml comment at the mobile-web-app step documents the substring semantics. A future workflow edit using a shorter but valid filter such as cross-version-wire/ would run the tests yet fail this guard. Matching with file.includes(path) mirrors Vitest; if the stricter root-anchored contract is intentional, a one-line comment would make that explicit.

…cluded file's job to fire on it

The coverage check counted any pr.yml job, including e2e, terminal IME and Windows WSL, which are
left out of verify.needs and so cannot block a merge. It now reads verify.needs and the reusable
workflows those jobs call.

It also only proved that some step names each excluded file, not that the job runs when the file
changes. The structured-session zsh login-shell test runs only in shell_contracts, whose path
trigger matched neither it, its harness nor its subject, so a PR touching only those ran it
nowhere. The check now asserts a change to each excluded file fires a gating job that names it,
and the shell trigger gains those three paths.
…e schema version-skew resolver

A change confined to src/shared/agent-turn-outcome (the arms a newer host publishes) or to
orchestration-schema-version-skew (how current code reopens a downgraded database) skipped the
job whose tests guard exactly those contracts. Also corrects the publish/read direction in the
turn-end comment.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ No new issues found in this delta. The guard rework is sound and the new assertions are load-bearing; the one prior suggestion on runByVitestStep's matching is unchanged, so this stays non-approving while that thread remains open.

Reviewed changes

  • Guard now counts only merge-gating jobs: gatingJobs() iterates verify.needs, parses each job's needs.code_paths.outputs.<name> == 'true' condition into a gate, and inherits a reusable workflow caller's gate into its jobs — so a file run only by a non-gating job (e2e, ime, wsl) no longer counts as covered.
  • New trigger assertion: a second test requires that a change to each excluded unit file fires the gate of the gating job that runs it, via classifyPrJobs([file])[gate].
  • Trigger-list additions: SHELL_PREFIXES gains the structured-session login-shell test, its harness and its subject; CROSS_VERSION_WIRE_PREFIXES gains agent-turn-outcome and orchestration-schema-version-skew, each pinned by pr-code-change-scope.test.mjs.
  • Timeout rationale: the orchestration downgrade test now records why it needs the 120 s budget.

I ran both changed CI-script tests (45 passing), enumerated every verify.needs job to confirm each vitest-running gating job parses a gate, and confirmed every added prefix maps to a real file and is load-bearing for classifyPrJobs.

Pullfrog  | Fix it ➔ | View workflow run | Using deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏

@brennanb2025

Copy link
Copy Markdown
Contributor Author

Review status: ready for a merge decision

Problem. The cross-version wire job ran a hand-typed list of test files. The main unit job skips that whole folder on purpose, so any file missing from the list ran in no CI job. Three files had been left out: cross-version-host-observed-turn-end, orchestration-delivery-downgrade and published-field-shape. Their checks (an older desktop reading turn-end values from a newer host, an older build opening a newer orchestration database, and the terminal field-shape helper) guarded nothing, and CI stayed green whether they passed or not.

What changes for you. Nothing in the app. In CI:

  • The job now runs the whole tests/e2e/cross-version-wire/ folder, so a new test there runs without editing the workflow.
  • A new check fails if any test file the main unit job skips is not run by a job that can block a merge, or if a PR editing only that file would not start that job.

Fixed during review (on top of the original two commits):

  • The coverage check counted jobs that can't block a merge (e2e, real IME, real WSL terminal) as coverage. It now counts only jobs in the final verify gate.
  • A shell test that predates this PR, structured-session-cli-login-shell.live-shell.test.ts, ran only in shell contracts, but editing it, its harness or the module it tests didn't start that job. Those paths now trigger it, and the check now requires this for every skipped file, so this kind of gap can't come back unnoticed.
  • Two modules the newly running tests check now start the cross-version job: the turn-outcome values and the orchestration schema-version handling.
  • The check scanned the repo's test files five times. It now scans twice, which saves about 8 to 14 s of one unit shard.
  • Two inaccurate comments were corrected: the direction of the turn-end test, and why the downgrade test needs 120 s.
  • Merged current main. The earlier static-analysis failure was main's own line-limit failure, which fix(native-chat): move the chat-tab surface out of the session host so main passes lint #24496 fixed.

Deferred (low severity, P3):

  • The check reads a job's trigger only in the needs.code_paths.outputs.X == 'true' form. A job written another way would be treated as always running. No job is written another way today, and existing tests pin every job's trigger and the gate list.
  • Lines that only mention a file (a shell comment, echo, --exclude) inside a vitest step can satisfy the check. Each would have to be written deliberately.
  • Equivalent spellings of the folder argument (no trailing slash, a ./ prefix) make the check fail. That's a false alarm, which is the safe direction.
  • The cross-version trigger is still a hand-kept list. Deriving it from the import graph isn't a clear win: the change-detection job installs no dependencies, and these tests' import closure is about 3,000 files, so the job would start on most PRs.
  • Minor style points in the new test.

Verified:

  • CI is green on 1e5e9a7. The cross-version job ran 13/13 files and 82/82 tests in about 58 s, against about 47 to 53 s before, with no job timeout at risk. The coverage check ran in unit shard 2/5. The branch merges cleanly with current main.
  • Locally, the coverage check fails against main's workflow and names exactly the three skipped files. Each new rule fails when its fix is removed: a file only the e2e job runs, the missing shell paths, and the missing cross-version paths.
  • All 33 files the unit job skips are each run by exactly one merge-blocking job, and an edit to the file starts that job.
  • 29 related CI-script test files pass (420 tests).

Not verified: no app or live QA, because this changes only CI and touches nothing in the app. The three newly running tests were not cold-started locally; CI covers the cold start.

@brennanb2025
brennanb2025 merged commit 444f195 into main Oct 2, 2026
35 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant