Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 3 additions & 14 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -860,21 +860,10 @@ jobs:
DIFF_BASE="$(node config/scripts/git-pull-request-diff-base.mjs "$BASE_SHA")"
pnpm run check:runtime-launcher-protocol-ratchet -- --base "$DIFF_BASE"

# A path filter that matches nothing exits 1 ("No test files found"), so this
# lane cannot report success while running zero tests.
# Runs the whole directory so a new file there cannot be left out; an empty match
# exits 1 ("No test files found"), so this lane cannot pass while running zero tests.
- name: Old/new client and server compatibility journeys
run: >-
pnpm exec vitest run --config config/vitest.config.ts
tests/e2e/cross-version-wire/release-checkout.unit.test.ts
tests/e2e/cross-version-wire/cross-version-browser-placement.unit.test.ts
tests/e2e/cross-version-wire/cross-version-terminal-wire.unit.test.ts
tests/e2e/cross-version-wire/reported-lossy-initial-snapshot.unit.test.ts
tests/e2e/cross-version-wire/cross-version-agent-session-wire.unit.test.ts
tests/e2e/cross-version-wire/cross-version-worktree-identity-downgrade.unit.test.ts
tests/e2e/cross-version-wire/cross-version-session-tabs-retirement-proof.unit.test.ts
tests/e2e/cross-version-wire/agent-session-resume-marker-downgrade.unit.test.ts
tests/e2e/cross-version-wire/agent-session-stop-event-downgrade.unit.test.ts
tests/e2e/cross-version-wire/cross-version-worktree-ps-verdict.unit.test.ts
run: pnpm exec vitest run --config config/vitest.config.ts tests/e2e/cross-version-wire/

managed_hook_node18:
name: managed hooks on Node 18
Expand Down
89 changes: 89 additions & 0 deletions config/scripts/ci-unit-exclusion-coverage.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { globSync, readFileSync } from 'node:fs'
import { parse } from 'yaml'
import { defaultExclude } from 'vitest/config'
import { describe, expect, it } from 'vitest'
import { CROSS_VERSION_WIRE_DIR, UNIT_INCLUDE, discoverUnitFiles } from './ci-unit-files.mjs'
import { classifyPrJobs } from './pr-code-change-scope.mjs'

function posixPaths(files) {
return files.map((file) => file.replaceAll('\\', '/'))
}

function workflowJobs(path) {
return parse(readFileSync(path, 'utf8')).jobs
}

// Why verify.needs: a job left out of it (e2e, ime, wsl) can be red or skipped without blocking a merge.
// Each gating job carries the code_paths output that decides whether it runs; a called workflow's jobs inherit the caller's.
function gatingJobs() {
const jobs = workflowJobs('.github/workflows/pr.yml')
return jobs.verify.needs.flatMap((name) => {
const { if: condition = '', uses } = jobs[name]
const gate = /needs\.code_paths\.outputs\.([\w-]+) == 'true'/.exec(condition)?.[1]
const called = uses?.startsWith('./.github/workflows/')
? Object.values(workflowJobs(uses.slice(2)))
: [jobs[name]]
return called.map((job) => ({ gate, pathArguments: vitestPathArguments(job) }))
})
}

// Path arguments of every step in the job that runs vitest; a trailing slash means a directory.
function vitestPathArguments(job) {
return (job.steps ?? [])
.map((step) => step.run)
.filter((run) => typeof run === 'string' && /\bvitest\b/.test(run))
.flatMap((run) => run.replaceAll('\\\n', ' ').split(/\s+/))
.map((token) => token.replace(/^['"]|['"]$/g, ''))
.filter((token) => /^(?:src|config|tests|mobile)\//.test(token))
}

function runByVitestStep(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.

)
}

// Why module scope: globbing the unit tree costs seconds, and every test reads the same result.
const UNIT_FILES = posixPaths(globSync(UNIT_INCLUDE, { exclude: defaultExclude }))
const SHARDED_UNIT_FILES = new Set(discoverUnitFiles())
const EXCLUDED_UNIT_FILES = UNIT_FILES.filter((file) => !SHARDED_UNIT_FILES.has(file))
const GATING_JOBS = gatingJobs()

describe('unit files kept out of the sharded test job', () => {
it('each still runs in a job that gates the PR', () => {
expect(EXCLUDED_UNIT_FILES.length).toBeGreaterThan(0)
// Why: an excluded file no gating step names guards nothing, and nothing else reports it.
expect(
EXCLUDED_UNIT_FILES.filter(
(file) => !GATING_JOBS.some((job) => runByVitestStep(file, job.pathArguments))
)
).toEqual([])
})

it('a change to each runs a gating job that names it', () => {
// Why: otherwise a PR editing only the file skips the one job that runs it.
expect(
EXCLUDED_UNIT_FILES.filter(
(file) =>
!GATING_JOBS.some(
({ gate, pathArguments }) =>
runByVitestStep(file, pathArguments) && (!gate || classifyPrJobs([file])[gate])
)
)
).toEqual([])
})

it('runs the whole cross-version-wire directory, not a list of its files', () => {
expect(GATING_JOBS.flatMap((job) => job.pathArguments)).toContain(CROSS_VERSION_WIRE_DIR)
})
Comment on lines +52 to +78

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',


it('names every cross-version-wire test so the unit include picks it up', () => {
// Why: a directory argument only reaches files the vitest include matches; any other name is silently skipped.
const tests = posixPaths(
globSync(`${CROSS_VERSION_WIRE_DIR}**/*.{test,spec}.{js,cjs,mjs,ts,tsx}`)
)
const included = new Set(UNIT_FILES)
expect(tests.length).toBeGreaterThan(0)
expect(tests.filter((file) => !included.has(file))).toEqual([])
})
})
5 changes: 4 additions & 1 deletion config/scripts/ci-unit-files.mjs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { globSync } from 'node:fs'
import { defaultExclude } from 'vitest/config'

// Why one constant: the cross-version-wire job runs this directory, so a new file there runs with no list to update.
export const CROSS_VERSION_WIRE_DIR = 'tests/e2e/cross-version-wire/'

export const UNIT_INCLUDE = [
'src/**/*.test.ts',
'src/**/*.test.tsx',
Expand Down Expand Up @@ -32,7 +35,7 @@ export const UNIT_EXCLUDE = [
'src/shared/posix-command-path-lookup.test.ts',
'tests/e2e/relay-region-compatibility.unit.test.ts',
'tests/e2e/relay-region-correction.unit.test.ts',
'tests/e2e/cross-version-wire/**'
`${CROSS_VERSION_WIRE_DIR}**`
]

export function discoverUnitFiles(root = process.cwd()) {
Expand Down
17 changes: 16 additions & 1 deletion config/scripts/pr-code-change-scope.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ const SHELL_PREFIXES = [
'src/main/shell-wrapper-',
'src/main/terminal-history-fish',
'src/main/zsh-',
'src/main/runtime/structured-session-cli-login-shell',
'src/main/runtime/structured-session-login-shell-test-harness',
'src/main/runtime/structured-session-child-identity-env',
'src/renderer/src/components/terminal-pane/fish-color-scheme',
'src/shared/fish-',
'src/shared/pty-reply-echo-shapes',
Expand Down Expand Up @@ -178,7 +181,19 @@ const CROSS_VERSION_WIRE_PREFIXES = [
'src/main/runtime/runtime-worktree-agent-',
'src/main/runtime/runtime-worktree-pty-agent-sources',
'src/shared/runtime-worktree-contracts',
'src/renderer/src/runtime/remote-runtime-terminal-multiplexer'
'src/renderer/src/runtime/remote-runtime-terminal-multiplexer',
// Turn-end status a newer host publishes and an older desktop reads (cross-version-host-observed-turn-end).
'src/shared/agent-turn-outcome',
'src/shared/agent-status-types',
'src/shared/agent-lead-status-fold',
'src/shared/agent-session-turn-record',
'src/shared/structured-agent-session-agent-status',
'src/shared/structured-agent-session-projection',
'src/shared/workspace-session-sleeping-agents',
// An older app opening a newer orchestration database (orchestration-delivery-downgrade).
'src/main/runtime/orchestration/db.ts',
'src/main/runtime/orchestration/db/',
'src/main/runtime/orchestration/orchestration-schema-version-skew'
]

const MANAGED_HOOK_PREFIXES = [
Expand Down
23 changes: 22 additions & 1 deletion config/scripts/pr-code-change-scope.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,23 @@ describe('per-job path classification', () => {
})
})

it('runs shell contracts for the structured-session login-shell test, its harness and its subject', () => {
expectClassification(
['src/main/runtime/structured-session-cli-login-shell.live-shell.test.ts'],
{ shell_contracts: true }
)
for (const file of [
'src/main/runtime/structured-session-login-shell-test-harness.ts',
'src/main/runtime/structured-session-child-identity-env.ts'
]) {
expectClassification([file], {
shell_contracts: true,
package: true,
package_windows: true
})
}
})

it('runs orcad browser when Chrome launch, session, or tab modules change', () => {
for (const file of [
'src/main/orcad/external-chromium-browser-session.ts',
Expand Down Expand Up @@ -367,7 +384,11 @@ describe('per-job path classification', () => {
'src/main/runtime/runtime-worktree-agent-rows.ts',
'src/main/runtime/runtime-worktree-pty-agent-sources.ts',
'src/shared/runtime-worktree-contracts.ts',
'src/renderer/src/runtime/remote-runtime-terminal-multiplexer.ts'
'src/renderer/src/runtime/remote-runtime-terminal-multiplexer.ts',
'src/shared/structured-agent-session-projection.ts',
'src/shared/agent-turn-outcome.ts',
'src/main/runtime/orchestration/db.ts',
'src/main/runtime/orchestration/orchestration-schema-version-skew.ts'
]) {
expectClassification([file], {
'cross-version-wire': true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { importReleaseCheckoutModule, materializeReleaseCheckout } from './relea
// Pin the last pre-v41 implementation: this contract specifically exercises status-only readers.
const PRE_V41 = 'aac38d698ff75ac4c8658addab48ef5a83617619'

// Why 120 s: a cold release checkout materializes in the test body, and its 45 s extraction deadline alone exceeds the 30 s default.
test('pre-v41 code opens, acknowledges and writes a current-schema database, then current code reopens it', async () => {
const checkout = await materializeReleaseCheckout(PRE_V41)
const baseline = await importReleaseCheckoutModule(
Expand Down Expand Up @@ -67,4 +68,4 @@ test('pre-v41 code opens, acknowledges and writes a current-schema database, the
db?.close()
rmSync(directory, { recursive: true, force: true })
}
})
}, 120_000)
Loading