Merge remote-tracking branch 'origin/master' into fix/coverage-fork-exit-order

This commit is contained in:
turtle1999 committed 2026-10-11 15:04:18 +08:00
commit 838c1e5f25
3 files changed
+38 -13

No files matched your search

@@ -153,11 +153,15 @@ jobs:
retention-days: 7
# Blacksmith x64 CI builds use 2 vCPU for compilation, bundling, and wheel smokes.
# Release macOS builds use larger GitHub runners; ordinary CI and direct
# builder dispatches retain the standard native target matrix.
build:
needs: [plan, sdk-wheel]
name: ${{ matrix.target }}
runs-on: >-
${{ inputs.ci && !inputs.release && matrix.target == 'node24-linux-x64'
${{ inputs.release && matrix.target == 'node24-macos-x64' && 'macos-15-large'
|| inputs.release && matrix.target == 'node24-macos-arm64' && 'macos-15-xlarge'
|| inputs.ci && !inputs.release && matrix.target == 'node24-linux-x64'
&& vars.DSH_CI_FAILOVER_LINUX == 'blacksmith' && 'blacksmith-2vcpu-ubuntu-2404'
|| inputs.ci && !inputs.release && matrix.target == 'node24-win-x64'
&& vars.DSH_CI_FAILOVER_WINDOWS == 'blacksmith' && 'blacksmith-2vcpu-windows-2025'
+26 -5
View File
@@ -111,6 +111,8 @@ interface ScrollWorld {
interface ScrollWorldOptions {
readonly failureShot: string
/** Install a controllable browser clock before boot; omitted worlds use real time. */
readonly controlledClock?: boolean
readonly paceMs?: number
readonly replay?: ReplayOverrideDoc
readonly seeds: readonly { fixture: ChatScrollFixture; id: string }[]
@@ -206,6 +208,7 @@ async function launchScrollWorld(options: ScrollWorldOptions): Promise<ScrollWor
scaffold.ctx.on('session/event', (_session, event: SessionEvent) => { events.push(event) })
scaffold.ctx.on('agent/assistant-stream', ({ frame }) => { assistantFrames.push(frame) })
page = await newEnglishPage(browser, 900)
if (options.controlledClock) await page.clock.install()
const tripwire = watchConsole(page)
await page.goto(scaffold.authenticatedUrl, { waitUntil: 'load' })
await page.waitForSelector('[class*="frame"]', { timeout: 30_000 })
@@ -590,8 +593,10 @@ describe('web e2e: long Chat scroll contract', () => {
const artifactRoot = fileURLToPath(new URL('../../../.artifacts/screenshots/visible-fold/', import.meta.url))
await mkdir(artifactRoot, { recursive: true })
const evidence = await mkdtemp(join(artifactRoot, `${scenario.name}-`))
const controlledClock = scenario.name === 'content-growth-during-fold' || scenario.name === 'cancel-all-during-fold'
await withScrollWorld({
failureShot: `visible-fold-${scenario.name}`,
controlledClock,
replay: [replayEntry(textStream('VISIBLE_FOLD_REPLY', 'VISIBLE_FOLD_DONE', 2))],
seeds: [{ fixture, id: `visible-fold-${scenario.name}` }],
}, async (world) => {
@@ -727,6 +732,7 @@ describe('web e2e: long Chat scroll contract', () => {
raceApplied = true
column.style.paddingBottom = '320px'
}
if (raceApplied) host.setAttribute('data-fold-race-applied', '')
}
const message = [...column.querySelectorAll<HTMLElement>('[data-submission-echo], [data-chat-flow-kind="user"]')]
.find(element => element.textContent?.includes(marker))
@@ -743,6 +749,7 @@ describe('web e2e: long Chat scroll contract', () => {
host.addEventListener('dsh-test-fold-stop', () => {
cancelAnimationFrame(frame); sample()
host.removeEventListener('dsh-test-fold-growth', markGrowth)
host.removeAttribute('data-fold-race-applied')
host.removeAttribute('data-fold-probe-ready'); resolveTrace(samples)
}, { once: true })
sample(); host.setAttribute('data-fold-probe-ready', ''); frame = requestAnimationFrame(tick)
@@ -752,11 +759,25 @@ describe('web e2e: long Chat scroll contract', () => {
let samples: Awaited<typeof trace> = []
try {
settled = world.scaffold.whenTurnSettled(30_000)
if (scenario.name === 'cancel-all-during-fold') {
await page.getByRole('button', { name: 'Send message', exact: true }).evaluate((button) => {
if (!(button instanceof HTMLButtonElement)) throw new Error('Send control is not a button')
button.click()
})
if (controlledClock) {
// Advance every animation frame so the race cannot miss the intermediate fold height.
await page.clock.pauseAt(await page.evaluate(() => Date.now() + 1000))
try {
await page.getByRole('button', { name: 'Send message', exact: true }).evaluate((button) => {
if (!(button instanceof HTMLButtonElement)) throw new Error('Send control is not a button')
button.click()
})
await expect.poll(async () => {
await page.clock.runFor(16)
return page.locator('[data-fold-race-applied]').count()
}, { timeout: 10_000 }).toBe(1)
await expect.poll(async () => {
await page.clock.runFor(16)
return page.locator('[data-chat-motion="collapse"]').count()
}, { timeout: 10_000 }).toBe(0)
} finally {
await page.clock.resume()
}
} else await page.getByRole('button', { name: 'Send message', exact: true }).click()
await promptBlocked.promise
await page.getByText(input, { exact: true }).waitFor()
+7 -7
View File
@@ -929,19 +929,19 @@ describe('Runtime and LLM e2e Blacksmith routing', () => {
it('keeps native release and dispatch builders hosted while routing x64 CI by platform', () => {
const workflow = loadWorkflow('.github/workflows/build-exe-for-python-sdk.yml')
const build = workflowJob(workflow, 'build')
for (const [target, runner, variable, blacksmith] of [
['node24-linux-x64', 'ubuntu-latest', 'DSH_CI_FAILOVER_LINUX', 'blacksmith-2vcpu-ubuntu-2404'],
['node24-win-x64', 'windows-2025', 'DSH_CI_FAILOVER_WINDOWS', 'blacksmith-2vcpu-windows-2025'],
['node24-linux-arm64', 'ubuntu-24.04-arm', 'DSH_CI_FAILOVER_LINUX', 'ubuntu-24.04-arm'],
['node24-macos-arm64', 'macos-latest', 'DSH_CI_FAILOVER_LINUX', 'macos-latest'],
['node24-macos-x64', 'macos-15-intel', 'DSH_CI_FAILOVER_LINUX', 'macos-15-intel'],
for (const [target, runner, variable, blacksmith, releaseRunner] of [
['node24-linux-x64', 'ubuntu-latest', 'DSH_CI_FAILOVER_LINUX', 'blacksmith-2vcpu-ubuntu-2404', 'ubuntu-latest'],
['node24-win-x64', 'windows-2025', 'DSH_CI_FAILOVER_WINDOWS', 'blacksmith-2vcpu-windows-2025', 'windows-2025'],
['node24-linux-arm64', 'ubuntu-24.04-arm', 'DSH_CI_FAILOVER_LINUX', 'ubuntu-24.04-arm', 'ubuntu-24.04-arm'],
['node24-macos-arm64', 'macos-latest', 'DSH_CI_FAILOVER_LINUX', 'macos-latest', 'macos-15-xlarge'],
['node24-macos-x64', 'macos-15-intel', 'DSH_CI_FAILOVER_LINUX', 'macos-15-intel', 'macos-15-large'],
] as const) {
for (const ci of [false, true]) {
for (const release of [false, true]) {
for (const mode of ['', 'selfhosted', 'unexpected', 'blacksmith']) {
const vars = { DSH_CI_FAILOVER_LINUX: 'blacksmith', DSH_CI_FAILOVER_WINDOWS: 'blacksmith', [variable]: mode }
expect(evaluateRunsOn(build['runs-on'], { inputs: { ci, release }, vars, matrix: { target, runner } }), `${target} ci=${ci} release=${release} mode=${mode}`)
.toBe(ci && !release && mode === 'blacksmith' ? blacksmith : runner)
.toBe(release ? releaseRunner : ci && mode === 'blacksmith' ? blacksmith : runner)
}
}
}