Skip to content

Commit ca75f77

Browse files
authored
Merge branch 'main' into fix/dataproduct-unhandled-rejection
2 parents 686d612 + e5f28d1 commit ca75f77

34 files changed

Lines changed: 2453 additions & 302 deletions

.github/playwright/impact-map.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@
215215
"playwright/e2e/Features/DataQuality/Profiler.spec.ts",
216216
"playwright/e2e/Features/DataQuality/ProfilerIngestionForm.spec.ts",
217217
"playwright/e2e/Features/IncidentManager.spec.ts",
218+
"playwright/e2e/Features/ServiceAgentsDeploymentSummary.spec.ts",
218219
"playwright/e2e/Features/ServiceAgentsLiveProgress.spec.ts",
219220
"playwright/e2e/Features/StorageMetadataAgentForm.spec.ts",
220221
"playwright/e2e/Features/TestSuite*.spec.ts",

.github/scripts/build_playwright_shards.py

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,15 +60,29 @@
6060
"search-rbac": 1,
6161
}
6262
TARGET_MS = 20 * 60 * 1000
63-
# The chromium lane has outgrown a 19-minute shard: at the COMMON_MAX_SHARDS
64-
# ceiling the heaviest shard is predicted at 19.2m, so full-mode planning aborts
65-
# and every merge-queue run fails before a single test runs. The binding limit
66-
# is the 25m `timeout` wrapper around `npx playwright test`, against which 21m
67-
# leaves ~4m; the 35m playwright-ci job clock is looser still, since
68-
# it also has to cover ~5-8m of setup and teardown around that wrapper.
69-
COMMON_SHARD_BUDGET_MS = 21 * 60 * 1000
63+
# Chromium shard budget, derived from the predicted→actual execution tail
64+
# rather than from the average. Measured on merge_group run 32219260486
65+
# (23 chromium shards, fresh auto-refreshed baseline): actual/predicted
66+
# execution ratio has median 0.96 — predictions are well calibrated — but
67+
# the tail reaches 1.08 on a healthy run and 1.23 on a noisy one
68+
# (chromium-01 in run 32209040146 was SIGTERM'd by the 25-minute wrapper
69+
# with 162/164 tests already passed). The binding constraint is that
70+
# budget × worst-tail-ratio must stay under the 1500-second wrapper:
71+
# 21 min × 1.23 = 1550 s → dead shard, all tests green (the outage)
72+
# 19 min × 1.23 = 1402 s → 98 s of margin
73+
# 19 min × 1.32 = 1500 s → break-even; tolerated tail is 1.32
74+
# 21 min was a stop-gap (#30784) to fit the lane under the old 24-shard
75+
# ceiling; the ceiling is now 28 (below), which is what actually makes a
76+
# 19-minute budget feasible again.
77+
COMMON_SHARD_BUDGET_MS = 19 * 60 * 1000
7078
EFFICIENCY = 0.85
71-
COMMON_MAX_SHARDS = 24
79+
# Raised 24 → 28 together with the budget revert above. Current chromium
80+
# content (~71,700 predicted worker-seconds) needs 25 shards at a
81+
# 19-minute budget — over the old cap, which is exactly why #30784 had to
82+
# raise the budget instead. 28 leaves ~12% content-growth headroom before
83+
# planning aborts; if the lane grows past that, split heavy suites (see
84+
# AUDITED_PARALLEL_SUITES) before considering another cap raise.
85+
COMMON_MAX_SHARDS = 28
7286
# Weight assigned to a test that has no timing evidence in `timing-baseline.json`
7387
# (or in any additional history payloads). Bumped from 20 s → 30 s alongside the
7488
# all-zero-history fix in `load_history`: a suite re-enabled after being

.github/scripts/evaluate_playwright_performance.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,11 +103,19 @@ def classify_targets(
103103
# specific shard(s) that exceeded the threshold (per the phase artifacts) so
104104
# the merge-queue error and the PR summary are useful without the raw log.
105105
BLOCKING_TARGET_DETAILS: dict[str, dict[str, Any]] = {
106+
# TRANSITIONAL: threshold widened from 300 → 480 s while the
107+
# `playwright-chromium-deps-v2` apt cache is still populating across
108+
# branches (a cache miss triggers a real apt install that can take
109+
# 6-7 min on a slow Azure mirror; a cache hit is <5 s). The keeps
110+
# step-level `timeout` wrappers on `install-deps` in the workflow are
111+
# bumped in lock-step to 8 min. Tighten back to 300 s once every
112+
# merge_group is a cache hit — see the shard-side comment in
113+
# playwright-e2e-reusable.yml.
106114
"environmentAtMostFiveMinutes": {
107115
"label": "Environment setup",
108116
"phase_field": "environmentSeconds",
109117
"unit": "s",
110-
"threshold": 300,
118+
"threshold": 480,
111119
},
112120
"executionAtMostTwentyFiveMinutes": {
113121
"label": "Maximum shard execution",
@@ -306,7 +314,8 @@ def main() -> None:
306314
),
307315
}
308316
targets = {
309-
"environmentAtMostFiveMinutes": metrics["maxEnvironmentSeconds"] <= 300,
317+
# Transitional 480 s ceiling — see BLOCKING_TARGET_DETAILS comment above.
318+
"environmentAtMostFiveMinutes": metrics["maxEnvironmentSeconds"] <= 480,
310319
# Aligned with the 25-minute wrapper on the shard step (`timeout … 25m`
311320
# in playwright-postgresql-e2e.yml, PR #30689). The previous 21-minute
312321
# ceiling was left over from before that wrapper bump and marked

.github/scripts/render_playwright_summary.cjs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -474,7 +474,10 @@ async function renderPlaywrightSummary({ github, context, core }) {
474474
classification: 'Blocking',
475475
metric: 'Environment setup',
476476
observed: `${displayMetric(performanceMetrics.maxEnvironmentSeconds)} s`,
477-
target: '≤ 300 s',
477+
// Transitional 480 s ceiling while the chromium apt cache is
478+
// populating across branches — see the BLOCKING_TARGET_DETAILS
479+
// comment in evaluate_playwright_performance.py.
480+
target: '≤ 480 s',
478481
passed: performanceTargets.environmentAtMostFiveMinutes,
479482
},
480483
{

.github/scripts/tests/test_playwright_ci_planning.py

Lines changed: 42 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -40,34 +40,40 @@ def test_basic_and_chromium_share_the_bounded_common_lane():
4040
planner = load_script("build_playwright_shards")
4141

4242
assert planner.PROJECT_LANES["Basic"] == "chromium"
43-
assert planner.lane_bounds("chromium", "full") == (5, 24)
43+
assert planner.lane_bounds("chromium", "full") == (
44+
5,
45+
planner.COMMON_MAX_SHARDS,
46+
)
4447

4548

46-
def test_full_common_shard_count_is_capped_at_24():
49+
def test_full_common_shard_count_is_capped_at_the_common_max():
4750
planner = load_script("build_playwright_shards")
51+
cap = planner.COMMON_MAX_SHARDS
52+
# Enough content to push the calculated shard count comfortably above
53+
# the cap — the exact figure is unimportant; we just need
54+
# `calculated > cap` so the min(cap, …) clamp is what returns.
4855
units = [
4956
planner.Unit(
5057
"chromium",
5158
f"{index}.spec.ts",
5259
str(index),
5360
weight_ms=1_000_000,
5461
)
55-
for index in range(81)
62+
for index in range(cap * 4)
5663
]
57-
units.append(
58-
planner.Unit("chromium", "remainder.spec.ts", "remainder", weight_ms=363_055)
59-
)
6064

61-
assert planner.shard_count(units, "chromium", "full") == 24
65+
assert planner.shard_count(units, "chromium", "full") == cap
6266

6367

6468
def test_common_lane_carries_its_own_shard_budget():
65-
# The chromium lane no longer sits a minute under TARGET_MS: the suite grew
66-
# past what COMMON_MAX_SHARDS could hold at 19m, so it now runs a minute
67-
# above the other lanes. Both still fit the 25m playwright timeout wrapper.
69+
# Chromium's budget is a minute UNDER the other lanes' TARGET_MS, derived
70+
# from the predicted→actual execution tail: actuals run up to 1.23× the
71+
# prediction on noisy runs (run 32209040146), and 19 min × 1.32 is the
72+
# break-even against the 25-minute playwright wrapper. See the derivation
73+
# comment on COMMON_SHARD_BUDGET_MS.
6874
planner = load_script("build_playwright_shards")
6975

70-
assert planner.shard_budget_ms_for_lane("chromium") == 21 * 60 * 1000
76+
assert planner.shard_budget_ms_for_lane("chromium") == 19 * 60 * 1000
7177
assert planner.shard_budget_ms_for_lane("search") == 20 * 60 * 1000
7278

7379

@@ -98,18 +104,26 @@ def test_common_assignment_stays_within_the_execution_ceiling():
98104
)
99105

100106

101-
def test_full_mode_chromium_converges_at_the_shard_ceiling():
102-
# Regression guard for the merge-queue outage: a lane of this shape exhausted
103-
# COMMON_MAX_SHARDS under the old 19m budget and aborted planning outright.
104-
# The allocator must converge at or before the ceiling, and the resulting
105-
# plan genuinely needs the window above 19m -- so quietly reverting the
106-
# budget to 19m fails on the final assertion rather than only in CI.
107+
def test_full_mode_chromium_converges_above_the_old_24_shard_ceiling():
108+
# Regression guard for BOTH historical outages on this lane:
109+
# 1. Under budget=19m × cap=24, content past ~1163 worker-minutes
110+
# exhausted the cap and aborted planning outright (the #30784
111+
# outage — its stop-gap was raising the budget to 21m).
112+
# 2. Under budget=21m, packed shards ran into the 25-minute wrapper on
113+
# tail-ratio runs (run 32209040146 — SIGTERM with 162/164 passed).
114+
# The durable configuration is budget=19m × cap=28: the allocator must
115+
# converge within the ceiling AND genuinely need more than 24 shards —
116+
# so quietly reverting COMMON_MAX_SHARDS to 24 fails here rather than
117+
# only in the merge queue. The content shape mirrors reality post
118+
# audit-splitting: many fine-grained units (1300 × 1 min ≈ today's
119+
# ~1200 worker-minutes of chromium content), not a few near-atomic
120+
# blocks whose granularity would distort LPT balance.
107121
planner = load_script("build_playwright_shards")
108122
units = [
109123
planner.Unit(
110-
"chromium", f"heavy-{index}.spec.ts", str(index), weight_ms=13 * 60 * 1000
124+
"chromium", f"fine-{index}.spec.ts", str(index), weight_ms=60_000
111125
)
112-
for index in range(96)
126+
for index in range(1300)
113127
]
114128

115129
shards = planner.assign_lane_within_budget(units, "chromium", "full")
@@ -120,7 +134,7 @@ def test_full_mode_chromium_converges_at_the_shard_ceiling():
120134
)
121135
assert len(shards) <= planner.COMMON_MAX_SHARDS
122136
assert heaviest_ms <= planner.COMMON_SHARD_BUDGET_MS
123-
assert heaviest_ms > 19 * 60 * 1000
137+
assert len(shards) > 24
124138

125139

126140
def test_full_mode_chromium_reports_a_lane_the_ceiling_cannot_hold():
@@ -132,7 +146,7 @@ def test_full_mode_chromium_reports_a_lane_the_ceiling_cannot_hold():
132146
for index in range(120)
133147
]
134148

135-
with pytest.raises(SystemExit, match=r"needs more than 24 shards"):
149+
with pytest.raises(SystemExit, match=r"needs more than 28 shards"):
136150
planner.assign_lane_within_budget(units, "chromium", "full")
137151

138152

@@ -992,27 +1006,27 @@ def test_hook_heavy_subsuites_in_audited_suite_stay_atomic():
9921006
]
9931007

9941008

995-
def test_common_shards_enforce_the_twenty_one_minute_budget(tmp_path):
1009+
def test_common_shards_enforce_the_nineteen_minute_budget(tmp_path):
9961010
planner = load_script("build_playwright_shards")
9971011
within_budget = planner.Unit(
9981012
"chromium",
9991013
"within.spec.ts",
10001014
"within",
10011015
grep_titles={("chromium", "within.spec.ts", "within")},
10021016
test_ids={"within"},
1003-
weight_ms=21 * 60 * 1000,
1017+
weight_ms=19 * 60 * 1000,
10041018
)
10051019
above_budget = planner.Unit(
10061020
"chromium",
10071021
"above.spec.ts",
10081022
"above",
10091023
grep_titles={("chromium", "above.spec.ts", "above")},
10101024
test_ids={"above"},
1011-
weight_ms=21 * 60 * 1000 + 1,
1025+
weight_ms=19 * 60 * 1000 + 1,
10121026
)
10131027

10141028
planner.write_plan(tmp_path, "chromium", 0, [within_budget])
1015-
with pytest.raises(SystemExit, match="above the 21-minute plan budget"):
1029+
with pytest.raises(SystemExit, match="above the 19-minute plan budget"):
10161030
planner.write_plan(tmp_path, "chromium", 1, [above_budget])
10171031

10181032

@@ -1893,11 +1907,13 @@ def test_performance_enforcement_still_fails_blocking_targets(tmp_path, monkeypa
18931907
}
18941908
)
18951909
)
1910+
# 481 > 480-s ceiling (transitional env target — see
1911+
# BLOCKING_TARGET_DETAILS in evaluate_playwright_performance.py).
18961912
phase_file.write_text(
18971913
json.dumps(
18981914
{
18991915
"lane": "chromium",
1900-
"environmentSeconds": 301,
1916+
"environmentSeconds": 481,
19011917
"executionSeconds": 1,
19021918
}
19031919
)
File renamed without changes.

0 commit comments

Comments
 (0)