Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
2950a4a
chore(devex): use match statements where dispatch reads clearer
arnohillen Aug 17, 2026
fe2268d
Merge branch 'master' into posthog/dc-match-statements
arnohillen Aug 21, 2026
762880b
feat(insights): add box plots to SQL insights
pauldambra Aug 26, 2026
f9ed930
refactor(insights): simplify SQL box plot display and chart code
pauldambra Aug 26, 2026
5ca3de7
fix(surveys): preserve newlines in hosted open text
lucasheriques Aug 26, 2026
59d49d3
chore(visual): update storybook baselines
posthog[bot] Aug 26, 2026
4a2fa60
fix(insights): handle trend results without actions
sampennington Aug 27, 2026
4f2478f
chore(deps): Update posthog-go to 1.24.3
posthog-js-upgrader[bot] Aug 27, 2026
38d7da6
chore(deps): update posthoganalytics to 7.44.2
posthog-js-upgrader[bot] Aug 27, 2026
1f27c99
chore(visual): update storybook baselines
posthog[bot] Aug 27, 2026
358adbe
chore(devex): add a CI prior-art lookup for ideas already tried
webjunkie Aug 27, 2026
4c5b6eb
chore(devex): rewrite the CI prior-art doc in Simplified Technical En…
webjunkie Aug 27, 2026
823432b
chore(devex): cover django perf and the runner trial in the prior-art…
webjunkie Aug 27, 2026
a0454fe
chore(devex): record that snob test selection is live
webjunkie Aug 27, 2026
36cdae9
fix(devex): size product shards against the right headroom
webjunkie Aug 27, 2026
821a81c
chore(devex): add the closed-unmerged PRs the first pass skipped
webjunkie Aug 27, 2026
6753556
chore(devex): fact-check every entry, drop three, add the person-tabl…
webjunkie Aug 27, 2026
78e01b7
fix(devex): unblock the timing refresh and derive the split margin
webjunkie Aug 27, 2026
76d69ea
Merge remote-tracking branch 'origin/master' into fix/devex-product-s…
webjunkie Aug 27, 2026
6185f00
chore(devex): mirror the shard-job changes into the depot shadows
webjunkie Aug 27, 2026
4c72c6f
Merge remote-tracking branch 'origin/master' into fix/devex-product-s…
webjunkie Aug 27, 2026
0802d17
fix(devex): keep the timing refresh alive when the cache misses
webjunkie Aug 27, 2026
f3ffedc
fix(devex): stop a near-budget test from exploding the shard count
webjunkie Aug 27, 2026
d5a0dcd
fix(devex): keep product jobs running on branches that have not rebased
webjunkie Aug 27, 2026
db31d9c
fix(devex): size a split from the duration distribution, not one max
webjunkie Aug 27, 2026
5776c3b
feat(error-tracking): simplify rule settings
hpouillot Aug 27, 2026
e95bda9
fix(devex): charge a split for the fragmentation contiguous cuts force
webjunkie Aug 27, 2026
0fa13e0
fix(replay): bill every recording regardless of reported source and sdk
TueHaulund Aug 27, 2026
e411acb
fix(devex): stop the refresh publishing a map with no product entries
webjunkie Aug 27, 2026
0946abc
fix(devex): let the test count outrank the two-shard floor
webjunkie Aug 27, 2026
1e26728
chore(replay): state the mobile meter as the exact complement of the …
TueHaulund Aug 27, 2026
a2b1544
chore(visual): update storybook baselines
posthog[bot] Aug 27, 2026
ea5d19a
Merge remote-tracking branch 'origin/master' into chore/devex-ci-thin…
webjunkie Aug 27, 2026
ffd95df
chore(devex): correct four entries and widen the skill pointers
webjunkie Aug 27, 2026
e203174
feat(error-tracking): remove severity feature flag gates
hpouillot Aug 27, 2026
3e5a2c1
chore(visual): update storybook baselines
hpouillot Aug 27, 2026
e0a0757
chore(visual): update storybook baselines
hpouillot Aug 27, 2026
fc3e2ac
Merging a2b1544579b04243753ea1e852237f5e7251f33c into trunk-temp/pr-9…
trunk-io[bot] Aug 27, 2026
4cba227
Merging fc3e2acbe2acbe67dec887091020b131dbdafa62 into trunk-temp/pr-9…
trunk-io[bot] Aug 27, 2026
025f132
Merging 1e267281f2c6ee881196d45f4bb4ab5128056662 into trunk-temp/pr-9…
trunk-io[bot] Aug 27, 2026
5e17b94
Merging 59d49d3beec3243ac15cbe85e25a20f92a290310 into trunk-temp/pr-9…
trunk-io[bot] Aug 27, 2026
348c0dd
Merging 5e17b948c1b4afd6c949345482e295470269451b into trunk-temp/pr-8…
trunk-io[bot] Aug 27, 2026
cbb3a08
Merging ffd95df8fd2b3a614e985aea862e83b9421d581e into trunk-temp/pr-8…
trunk-io[bot] Aug 27, 2026
ac0778d
Merging 0946abcb1415c0cc317f9c7c8961d87b1c16d6b5 into trunk-temp/pr-8…
trunk-io[bot] Aug 27, 2026
87bc352
Merging ac0778d36506f7806b0a26cecda832dbce9fa6d5 into trunk-temp/pr-8…
trunk-io[bot] Aug 27, 2026
2e49e65
Merging fe2268d90aa4e911962e1254bb7dc8234d3681ab into trunk-temp/pr-8…
trunk-io[bot] Aug 27, 2026
09d2bba
Merging 5ca3de74011f9dce760a135e53120582ddeef8ec into trunk-temp/pr-8…
trunk-io[bot] Aug 27, 2026
1b5bdf2
Merging 09d2bba68b6244223c853a1e448f97e78947966a into trunk-temp/pr-8…
trunk-io[bot] Aug 27, 2026
ec41282
Merging 1f27c99fddbf86fe8f9e8fe4a6e3ce93e53d4116 into trunk-temp/pr-8…
trunk-io[bot] Aug 27, 2026
c47f854
Merging e0a07573035e4c3c2a75a6ac654a30c517d5e081 into trunk-temp/pr-8…
trunk-io[bot] Aug 27, 2026
5415da6
Merging 09d2bba68b6244223c853a1e448f97e78947966a into trunk-temp/pr-8…
trunk-io[bot] Aug 27, 2026
04a4dc9
Merging c47f8543ff44d9ff7fd055b2a1597b4d62f03d29 into trunk-temp/pr-8…
trunk-io[bot] Aug 27, 2026
434a9af
Merging 38d7da6efcdd0c8be823f1136d0d4917b4ff1496 into trunk-temp/pr-8…
trunk-io[bot] Aug 27, 2026
c4eb99f
Merging 4f2478fb525011c45a80d7d7320f6c1d4f7ddf17 into trunk-temp/pr-8…
trunk-io[bot] Aug 27, 2026
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
2 changes: 2 additions & 0 deletions .agents/skills/authoring-ci-workflows/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ description: >

# Authoring CI workflows

Before you propose a change to CI, check [things already tried](../../../docs/internal/ci-things-already-tried.md) for the idea. It records what was measured, and why some good-sounding changes were reverted or rejected.

Conventions for `.github/workflows/**` and `.github/actions/**`.
The linters own the mechanical rules (below); this skill is the **judgment calls** they can't enforce.

Expand Down
2 changes: 2 additions & 0 deletions .agents/skills/debugging-ci-failures/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ description: >

# Debugging PostHog CI failures

Before you propose a change to CI, check [things already tried](../../../docs/internal/ci-things-already-tried.md) for the idea. It records what was measured, and why some good-sounding changes were reverted or rejected.

Find the first meaningful failure, classify it, reproduce the smallest useful
case locally when appropriate, and report the result. Avoid public-visible or
irreversible actions unless the user explicitly asks.
Expand Down
2 changes: 2 additions & 0 deletions .agents/skills/depot-container-builds/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ description: >

# Depot Container Builds

Before you propose a change to CI, check [things already tried](../../../docs/internal/ci-things-already-tried.md) for the idea. It records what was measured, and why some good-sounding changes were reverted or rejected.

Depot runs Docker image builds on remote high-performance builders (16 CPU, 32 GB RAM, NVMe SSD cache). `depot build` is a drop-in replacement for `docker build` / `docker buildx build`. `depot bake` replaces `docker buildx bake`.

## Project Selection for Multi-Org Users
Expand Down
2 changes: 2 additions & 0 deletions .agents/skills/django-migrations/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ description: Django migration patterns and safety workflow for PostHog. Use when

# Django migrations

Before you propose a change to the migration history or to how migrations run, check [things already tried](../../../docs/internal/ci-things-already-tried.md). It records the closed attempts at squashing the history and at the Person table cutover.

Read these files first, before writing or editing a migration:

- `docs/published/handbook/engineering/developing-locally.md` (`## Django migrations`, `### Non-blocking migrations`, `### Resolving merge conflicts`)
Expand Down
2 changes: 2 additions & 0 deletions .agents/skills/fixing-flaky-tests/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ description: >

# Fixing flaky tests

Before you propose a change to how the suite runs in CI, check [things already tried](../../../docs/internal/ci-things-already-tried.md). It records measured verdicts on test parallelism, sharding, and coverage-based selection, so a rejected approach is not rebuilt.

Three non-negotiables, in order:

1. **Reproduce before you fix.** A fix for a failure you never observed is a guess.
Expand Down
2 changes: 2 additions & 0 deletions .agents/skills/improving-drf-endpoints/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ description: Use when editing, reviewing, or auditing DRF viewsets and serialize

# Improving DRF Endpoints

Before you propose a contract test against the generated OpenAPI schema, check [things already tried](../../../docs/internal/ci-things-already-tried.md). Six PRs took that idea, and none merged.

## Overview

Serializer fields are the source of truth for PostHog's entire type pipeline:
Expand Down
2 changes: 2 additions & 0 deletions .agents/skills/isolating-product-facade-contracts/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ description: Plan and execute product isolation migrations to a facade plus cont

# Isolating a product with facade and contracts

Before you choose a product to isolate, check [things already tried](../../../docs/internal/ci-things-already-tried.md). It records which product was the first candidate, and why the field test moved to another one.

Use this skill to migrate an existing product to the isolated architecture used by Visual review.
Optimize for short calendar exposure, not small diffs: authoring is cheap and the verification
chain catches mechanical breakage, while human review latency and a fast-moving master are the
Expand Down
2 changes: 2 additions & 0 deletions .agents/skills/maintaining-python-tests/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ description: >

# Maintaining Python tests

Before you propose a change to how the suite runs in CI, check [things already tried](../../../docs/internal/ci-things-already-tried.md). It records measured verdicts on test parallelism, sharding, and coverage-based selection, so a rejected approach is not rebuilt.

Use this skill for an existing Python test suite. Use `/writing-tests` before adding or substantially changing coverage. Use `/fixing-flaky-tests` when intermittent failure is the main problem.

The goal is not a smaller test count. The goal is a suite that catches the same realistic regressions with less compute, less waiting, and less maintenance.
Expand Down
2 changes: 2 additions & 0 deletions .agents/skills/stacking-prs/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ description: >

# Stacked PRs with `gh stack`

Before you divide a change into layers, check [things already tried](../../../docs/internal/ci-things-already-tried.md). It records when a stack cost more review effort than one PR.

GitHub's native stacked PRs are enabled on this repo.
A stack is an ordered chain of PRs where each one targets the branch of the PR below it; the bottom PR targets `master`.
GitHub tracks the chain as a first-class object: the PR UI shows a stack map, branch protections (code owner approval, required checks) apply to **every** layer including mid-stack ones, and CI that runs on `master` PRs runs on every layer.
Expand Down
30 changes: 22 additions & 8 deletions .depot/workflows/ci-backend-update-test-timing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,14 @@ jobs:
posthog-test-durations-

- name: Set the previous map aside
# .test_durations is not tracked, so there is nothing to restore it from
# and a cache miss leaves no file at all.
run: |
cp .test_durations /tmp/previous_durations
git checkout -- .test_durations
if [ -f .test_durations ]; then
mv .test_durations /tmp/previous_durations
else
echo "::warning::No cached map restored; a drifting Products slice has no stand-in"
fi

- name: Download timing artifacts
env:
Expand Down Expand Up @@ -103,12 +108,21 @@ jobs:
set -e
if [ "$products_status" -ne 0 ]; then
echo "::warning::Products durations refresh exited $products_status; keeping the previous products slice. Drift or an incomplete JUnit set are the expected causes, see the log above."
# Only entries the fresh slices do not carry: the outlier merge would
# otherwise let a stale value here beat a fresh one for the same test.
jq -s 'add' $(ls /tmp/core_durations /tmp/temporal_durations 2>/dev/null) > /tmp/fresh_durations
jq --slurpfile fresh /tmp/fresh_durations \
'with_entries(select((.key | startswith("products/")) and ($fresh[0][.key] == null)))' \
/tmp/previous_durations > /tmp/products_durations
if [ -f /tmp/previous_durations ]; then
# Only entries the fresh slices do not carry: the outlier merge would
# otherwise let a stale value here beat a fresh one for the same test.
jq -s 'add' $(ls /tmp/core_durations /tmp/temporal_durations 2>/dev/null) > /tmp/fresh_durations
jq --slurpfile fresh /tmp/fresh_durations \
'with_entries(select((.key | startswith("products/")) and ($fresh[0][.key] == null)))' \
/tmp/previous_durations > /tmp/products_durations
else
# No cached slice to stand in and no fresh one. A map with no product
# entries would still become the newest cache and the latest successful
# artifact, so every consumer would fall back to the file-count estimate
# and under-shard the fixture-heavy products. Leave the older map newest.
echo "::error::Products slice failed with no previous map to stand in; refusing to publish a map without product entries"
exit 1
fi
fi
uv run .github/scripts/optimize_test_durations.py .test_durations \
--merge-files /tmp/core_durations /tmp/temporal_durations /tmp/products_durations \
Expand Down
50 changes: 41 additions & 9 deletions .depot/workflows/ci-backend.yml
Original file line number Diff line number Diff line change
Expand Up @@ -942,8 +942,15 @@ jobs:
- name: Run product tests
# --force: discover already decided this product needs testing, skip turbo cache
# --log-order=stream: stream pytest output live instead of buffering until completion
# pytest_args: optional pytest-split flags for sharded products (e.g. "-- --splits 3 --group 1")
# legs: one turbo invocation per entry, each with its own pytest-split flags
# (e.g. "-- --splits 3 --group 1"). A job holds several legs when a split
# product's last shard had budget left over for whole small products, and
# pytest-split flags must not leak from that shard onto its job-mates.
env:
PRODUCT_LEGS: ${{ toJSON(matrix.legs) }}
# Read only when an unrebased branch planned the pre-legs shape.
LEGACY_FILTERS: ${{ matrix.filters }}
LEGACY_PYTEST_ARGS: ${{ matrix.pytest_args }}
CLICKHOUSE_HOGQL_USE_NEW_EVENTS_SCHEMA: ${{ matrix.new-events-schema && 'true' || 'false' }}
# products/tasks/backend/temporal moved here from the Django Temporal
# segment, and its conftest and workflows talk to Modal. Injected only
Expand All @@ -965,17 +972,42 @@ jobs:
# bin-packed buckets (each product writes its own file) and split products (unioned later).
# sysmon: Python 3.12+'s low-overhead coverage backend, ~a few % vs ~20% for the C tracer.
COVERAGE_CORE: sysmon
shell: bash
run: |
set +e
pnpm turbo run backend:test ${{ matrix.filters }} --concurrency=1 --output-logs=full --force --log-order=stream ${{ matrix.pytest_args }}
exit_code=$?
set -e
if [ $exit_code -eq 5 ]; then
echo "No tests collected for this shard, this is expected when splitting tests"
exit 0
else
exit $exit_code
overall=0
# A workflow edit reaches an open PR before the script edit does, so a
# branch that has not rebased still plans the flat {filters, pytest_args}
# shape. Normalize that into one leg rather than requiring the new key.
if [ -z "$PRODUCT_LEGS" ] || [ "$PRODUCT_LEGS" = "null" ]; then
PRODUCT_LEGS=$(jq -cn --arg f "$LEGACY_FILTERS" --arg a "$LEGACY_PYTEST_ARGS" \
'[{filters: $f, pytest_args: $a}]')
echo "Matrix entry carries no legs; running the legacy single invocation"
fi
leg_count=$(jq 'length' <<< "$PRODUCT_LEGS")
# Neither shape present means the job would pass having run no tests, and
# the rollup gate only reads this step's outcome. Fail loudly instead.
if [ -z "$leg_count" ] || [ "$leg_count" -lt 1 ]; then
echo "::error::No test legs in this matrix entry; refusing to pass without running tests"
exit 1
fi
for ((leg_index = 0; leg_index < leg_count; leg_index++)); do
leg_filters=$(jq -r ".[$leg_index].filters" <<< "$PRODUCT_LEGS")
leg_args=$(jq -r ".[$leg_index].pytest_args" <<< "$PRODUCT_LEGS")
echo "::group::turbo backend:test $leg_filters $leg_args"
# Word splitting is intended here: both variables carry several flags.
# shellcheck disable=SC2086
pnpm turbo run backend:test $leg_filters --concurrency=1 --output-logs=full --force --log-order=stream $leg_args
exit_code=$?
echo "::endgroup::"
if [ $exit_code -eq 5 ]; then
echo "No tests collected for this leg, this is expected when splitting tests"
elif [ $exit_code -ne 0 ]; then
overall=$exit_code
fi
done
set -e
exit $overall
# Lightweight repo-wide checks that only need Python + uv (no Docker/DB).
# Consolidates checks that previously each spun up their own runner.
repo-checks:
Expand Down
109 changes: 106 additions & 3 deletions .github/scripts/turbo-discover-sizing.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
const test = require('node:test')
const assert = require('node:assert/strict')

const { pruneDeadDurations, getSegmentDuration, calculateShards, resolveProductSizing, buildMatrix, PRODUCT_JOB_OVERHEAD_SECONDS, PRODUCT_SAFETY_FACTOR, TARGET_WALL_SECONDS } = require('./turbo-discover.js')
const { pruneDeadDurations, getSegmentDuration, calculateShards, resolveProductSizing, buildMatrix, productSplitShards, PRODUCT_JOB_OVERHEAD_SECONDS, TARGET_WALL_SECONDS } = require('./turbo-discover.js')

// A path that exists in every checkout, so the existence check is deterministic.
const LIVE_FILE = '.github/scripts/turbo-discover.js'
Expand Down Expand Up @@ -95,8 +95,8 @@ test('buildMatrix splits a product to the shared wall target', () => {

const matrix = buildMatrix(['big-one'], union, true)

// 2000s of work, with the safety factor, over a (target - overhead) budget per shard.
assert.equal(matrix.length, Math.ceil((2000 * PRODUCT_SAFETY_FACTOR) / (TARGET_WALL_SECONDS - O)))
// 2000s of work, with the imbalance margin, over a (target - overhead) budget.
assert.equal(matrix.length, productSplitShards({ work: 2000, heavyCount: 0, lightWork: 2000, maxLight: 50, testCount: 40 }))
assert.match(matrix[0].group, /^big-one \(1\/\d+\)$/)
})

Expand All @@ -107,5 +107,108 @@ test('buildMatrix leaves a small product packed', () => {

assert.equal(matrix.length, 1)
assert.equal(matrix[0].group, 'small-one')
assert.deepEqual(matrix[0].legs, [{ filters: '--filter=@posthog/products-small-one', pytest_args: '' }])
})

test('a single-invocation entry keeps the pre-legs keys for unrebased branches', () => {
// A workflow edit lands on an open PR before this script does, so an old
// workflow reading matrix.filters must still find something to run.
const union = { 'products/small_one/backend/test_c.py::test_c': 100 }

const matrix = buildMatrix(['small-one'], union, true)

assert.equal(matrix[0].filters, '--filter=@posthog/products-small-one')
assert.equal(matrix[0].pytest_args, '')
})

test('productSplitShards sizes the worst chunk, not the mean', () => {
const budget = TARGET_WALL_SECONDS - PRODUCT_JOB_OVERHEAD_SECONDS
const evenly = { work: 1000, heavyCount: 0, lightWork: 1000, maxLight: 10, testCount: 100 }
const coarse = { work: 1000, heavyCount: 0, lightWork: 1000, maxLight: 150, testCount: 100 }

// Same total work; the coarser grain cannot be cut as finely, so it needs more
// shards to keep its worst chunk inside the budget.
assert.ok(productSplitShards(coarse) > productSplitShards(evenly))
assert.ok(evenly.lightWork / productSplitShards(evenly) + evenly.maxLight <= budget)
assert.ok(coarse.lightWork / productSplitShards(coarse) + coarse.maxLight <= budget)
})

test('tests above half the budget each hold a shard of their own', () => {
const budget = TARGET_WALL_SECONDS - PRODUCT_JOB_OVERHEAD_SECONDS
const heavy = Math.ceil(budget * 0.8)

// Ten tests this size cannot pair, so no count below ten holds the budget,
// however the total work divides.
assert.equal(productSplitShards({ work: heavy * 10, heavyCount: 10, lightWork: 0, maxLight: 0, testCount: 10 }), 10)
// One heavy test and a sliver stays bounded rather than asking for a shard per
// second of remainder. Two tests cannot fill three shards, so the count stops
// there rather than planning one that collects nothing.
assert.equal(
productSplitShards({ work: budget + 1, heavyCount: 1, lightWork: 1, maxLight: 1, testCount: 2 }),
2
)
})

test('the count never exceeds the tests there are to place', () => {
// The fragmentation charge assumes a shape the suite may not have. Past the
// test count a shard collects nothing and spends a runner for it.
const many = { work: 10000, heavyCount: 3, lightWork: 100, maxLight: 10, testCount: 5 }

assert.equal(productSplitShards(many), 5)
})

test('a product holding one test is never split', () => {
const budget = TARGET_WALL_SECONDS - PRODUCT_JOB_OVERHEAD_SECONDS

// One test over the budget still gets one job: a second would collect nothing,
// and no split shortens the first.
assert.equal(
productSplitShards({ work: budget + 1, heavyCount: 1, lightWork: 0, maxLight: 0, testCount: 1 }),
1
)
})

test('a heavy test between light ones splits the light run', () => {
// Ordered [53, 301, 133] against a 320s budget: either contiguous cut leaves a
// 354s or 434s chunk, so two shards cannot hold the budget however it is cut.
assert.equal(productSplitShards({ work: 487, heavyCount: 1, lightWork: 186, maxLight: 133, testCount: 3 }), 3)
})

test('a product that fits one shard is packed, not split by its own margin', () => {
// 300s of work sits under the (target - overhead) budget, so the margin must
// not be what pushes it over into a two-way split.
const union = {}
for (let i = 0; i < 10; i++) {
union[`products/mid_one/backend/test_${i}.py::test_${i}`] = 30
}

assert.ok(300 <= TARGET_WALL_SECONDS - PRODUCT_JOB_OVERHEAD_SECONDS)
assert.equal(productSplitShards({ work: 300, heavyCount: 0, lightWork: 300, maxLight: 30, testCount: 10 }), 1)

const matrix = buildMatrix(['mid-one'], union, true)

assert.equal(matrix.length, 1)
assert.equal(matrix[0].group, 'mid-one')
})

test("a split product's last shard absorbs a small product without leaking split flags", () => {
const union = {}
for (let i = 0; i < 11; i++) {
union[`products/big_one/backend/test_${i}.py::test_${i}`] = 30
}
union['products/small_one/backend/test_s.py::test_s'] = 40

assert.equal(productSplitShards({ work: 330, heavyCount: 0, lightWork: 330, maxLight: 30, testCount: 11 }), 2)

const matrix = buildMatrix(['big-one', 'small-one'], union, true)

// Two jobs, not three: small-one rides along in the lighter second shard.
assert.equal(matrix.length, 2)
const shared = matrix.find((entry) => entry.group.includes('small-one'))
assert.equal(shared.group, 'big-one (2/2), small-one')
assert.equal(shared.legs.length, 2)
assert.match(shared.legs[0].pytest_args, /--splits 2 --group 2/)
// The whole product runs in its own leg, so it never sees --splits/--group.
assert.equal(shared.legs[1].filters, '--filter=@posthog/products-small-one')
assert.equal(shared.legs[1].pytest_args, '')
})
Loading
Loading