trunk-merge/pr-83663/efc82b1c-07a5-49eb-a7c7-354a9f6f924b - #90047
Closed
trunk-io[bot] wants to merge 40 commits into
Closed
trunk-merge/pr-83663/efc82b1c-07a5-49eb-a7c7-354a9f6f924b#90047trunk-io[bot] wants to merge 40 commits into
trunk-io[bot] wants to merge 40 commits into
Conversation
Convert five dispatch ladders (isinstance chains, len()+index probing of field chains, nested dict.get() probing) to match statements using class patterns with field capture, or-patterns, guards, sequence patterns, and mapping patterns. Behavior is unchanged: every branch of each old ladder maps to exactly one case, in the original order or one proven equivalent. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Generated-By: PostHog Desktop Task-Id: 3cb06508-6ac6-4768-a330-4495ac21001e
Add a Box plot option to SQL insights, gated behind the sql-box-plot-insight feature flag. Maps one row per X-axis and series pair into grouped boxes, auto-maps conventional names for minimum, percentiles, median, mean, and maximum, and keeps percentile calculation in SQL instead of using limited browser results. Adopted from PR #84558. Rebased onto master to resolve merge conflicts and squashed into a single commit. Generated-By: PostHog Desktop Task-Id: f1e69bea-f4e6-44cf-bd12-dc81f8a435c3
Extract the repeated single-Y-axis boolean into a named isSingleAxisChart flag in the display tab, and reuse one height-class expression for the box plot chart's empty, error, and success states. No behavior change. Generated-By: PostHog Desktop Task-Id: f1e69bea-f4e6-44cf-bd12-dc81f8a435c3
Leave Enter to the hosted survey textarea and rely on the survey SDK Cmd/Ctrl+Enter shortcut for submission. Keep the editor preview hints aligned with respondent behavior. Verified with the external survey backend suite, frontend typecheck, CI preflight, and focused Oxlint and Oxfmt checks.
6 updated Run: 15e93842-9e54-48e9-b856-6eced8bb9c0e Co-authored-by: pauldambra <984817+pauldambra@users.noreply.github.com>
CI ideas get re-proposed because the evidence against them is scattered across closed PRs and revert commits nobody greps. The same handful keeps coming back: xdist in the shards, BuildKit cache mounts, sharding the E2E suite, coverage-based test selection. Adds docs/internal/ci-things-already-tried.md, keyed by the proposal rather than the symptom, because the lookup happens when someone has an idea, not when they are debugging. Each entry carries the verdict, the date, the measurement, and a line of alternate phrasings so a differently-worded grep still lands. Verdicts are not bans. Every entry states the specific blocker so a reader can check whether it still holds; runner sizes and tooling move. Seeded from Julian's merged, reverted, and abandoned PRs since Oct 2025. Narrowed with local git: revert titles, plus lines added in one PR and removed in a later one across the CI hot files. That cut 847 PRs to 333 candidates, then to the entries here. The five CI skills that would otherwise carry duplicate copies get a one-line pointer instead.
…glish The first draft read like PR prose: idioms, passive constructions, and long sentences that carry two ideas. Agents and non-native speakers both parse that worse, and this file exists to be scanned fast during a lookup. Rewrites to ASD-STE100 writing rules while keeping full vocabulary: active voice, simple tenses, one idea per sentence, consistent terms for the same thing. Now averages under 10 words per sentence with none over 25. No entries, verdicts, or PR links changed.
… doc Paul's original ask in #team-devex named three areas: CI, django perf, and tests. The first pass covered CI and tests only. Adds a Django performance section that points at django-startup-time.md as the deep source, plus the three proposals that keep coming back: squashing the migration history (#48267, effect on timing too small for the blocker work), pydantic defer_build (reverted, relocated cost onto the first query after a deploy), and dropping pydantic from the generated schema (250+ model_validate callers make it non-local; the import cost was solved by evicting the module from django.setup instead). Also adds the Blacksmith runner trial (#54559 to #57991). Nothing in the repo recorded why the shadow existed or why it went away, and compare-ci-runners.py is still sitting there marked legacy. Vendor benchmark numbers stay out. They are unpublished internal measurements of a named third party, and the trial's own conclusion was that cache-state asymmetry, not runner speed, drove the large gaps.
An agent recently read CI, found no pytest-snob in pyproject.toml, and concluded the selector was dead. It isn't: pytest-snob is an inline PEP 723 dependency of tools/snob_backend_test_selection_shadow.py, so it never appears in the dependency file. The narrow scope added to the confusion. Selection ran on drafts only for a while, deliberately, until the merge queue was stable. #85530 extended it to ready PRs and #88265 folded Django and product selection into one job. This is the exact question the doc exists to answer, so it gets an entry rather than a correction in a thread.
PRODUCT_SAFETY_FACTOR was a single 1.3 covering two unrelated risks. On a packed bucket the products run sequentially, so the job's wall is the sum of its parts and there is no mean-versus-max gap to cover. The 30% markup there only bought extra buckets, each paying the base overhead again. On a split product the factor is load-bearing: sizing solves for the mean shard while the run's wall is the max, and nothing else bridges that. Split it in two. Buckets get 1.1, covering durations-map error alone. Splits get a margin interpolated from the measured max/mean at p90, which rises with the shard count because the max is an order statistic over more shards. Resolving that needs a fixed point, seeded at no margin so a product that fits one shard is not split in two by its own headroom. Product test jobs now carry legs, one turbo invocation each with its own pytest-split flags, so a split product's last shard can share a job with whole products without --splits/--group leaking onto them. The packer can seed from those remainders. It does not fire yet: with the margin reserved on every shard there is almost no modeled spare, and the real spare, a trailing-shard taper, is not something the sizer can see today. Landing the mechanism now keeps it inert until the margin drops. DEDICATED_BUCKET_PRODUCTS drops batch-exports. It was listed for an async-fixture teardown hang; it now runs at the median product failure rate with no job near the timeout, and the branch was unreachable regardless since the split path is checked first. The set stays as the extension point, with the criterion for re-adding written down. Also corrects the end-to-end claim in the sizing comment. The pre-shard preamble measures about 5.5 minutes, so a 12-minute shard target puts a full PR run near 19 minutes, not 15. Claude-Session: https://claude.ai/code/session_01EJ1y3UzXR1BKtukE886ks9
The first pass filtered closed PRs to those with a closing comment over 60 characters, which covered 34 of 125. That threw away the stale-bot closures, where the body still records exactly what was tried and why it stopped. Adds the ideas that get re-proposed most: Tilt over mprocs, sharing the dev environment across worktrees (three separate attempts), sparse-checkout on the big CI workflows, moving ee/ into products/, session-scoped django_db_setup, and six unmerged attempts at validating responses against the OpenAPI schema. Two existing entries were wrong by omission and are corrected. BuildKit cache mounts were rejected in bulk, then adopted narrowly for uv, which then cached wheels built against a different libxmlsec1 and broke the image; the fix that stuck puts the library version in the cache ID. Migration squashing had a second attempt on a different design, and that one also stalled. Both corrections came from checking present-day state rather than trusting the verdict in the PR, which is the habit the doc asks readers to have.
…e saga Ran a per-entry check of all 32 entries against PR metadata, PR bodies and comments, and present-day repo state. 29 held up. Three did not, and all three failed the same way: the PR was trusted over the repo. - The Tilt entry claimed bin/mprocs.yaml is still the process list. It is not. bin/start defaults to phrocs, which landed in #50341 back in March and reads a config generated per run by hogli dev:generate. - The SeaweedFS entry dated the first attempt to Mar 2026. The real first attempts were Sep and Oct 2025, the replay store migration merged in Nov 2025, and the PR that actually shipped the objectstorage swap (#60432) was never cited. The one PR it did cite never merged. - The xdist entry quoted 42.8%. No source says that. The closing comment gives rounded wall times, so the entry now gives those. Two claims were mine rather than the record's, and are marked or removed. The Blacksmith trial's duration and its cache-asymmetry conclusion are not in either PR, so the entry now says the detail lives in a team-channel report it cannot show. The sparse-checkout entry stated a rejection reason that nobody ever wrote: no human reviewed that PR, the stale bot closed it. It also described a diff that touched three workflows when it touched two, and missed that ci-rust.yml already used sparse-checkout beforehand. Removes Tilt, SeaweedFS, and Granian. None for being old. Tilt's subsystem was rebuilt around it, and the other two shipped, so neither failure is a live trap. Adds a "Remove an entry" section so the next removal has a rule to cite. The oldest entry in the file, xdist from October, stays: it is still the most re-proposed idea here. Adds the person-table cutover, eight unmerged PRs from November trying five mechanisms to repoint the Person model at a partitioned table. Person access now goes through the personhog client, so a Django-level cutover is no longer where that problem lives.
The timing workflow has failed on every run since .test_durations left the
repo. That PR stripped the commit machinery from this workflow but left a
`git checkout -- .test_durations` behind, and the file is now untracked and
gitignored, so the step errors:
error: pathspec '.test_durations' did not match any file(s) known to git
Consequence: no map has been published since. Every consumer has been
planning against a cache entry from before the duration floor was removed,
so that fix has never actually reached CI. Drop the checkout, and guard the
copy — the cache restore is best-effort and there is no tracked file behind
it any more.
With an unfloored map in hand the fitted split margin is wrong. It was
calibrated against shards planned on a floored map, where tens of thousands
of tiny parametrized tests carried ten times their real weight and the
partition only looked balanced. Replaying the real map through the splitter
puts max/mean at 1.02, not the 1.12-1.32 the table assumes, so the table
would now buy shards nothing needs.
Derive it instead. pytest-split cuts between tests and never inside one, so
a contiguous split's worst chunk runs at most one whole test past the mean.
Sizing the worst chunk rather than the mean gives
work / n + maxTest <= budget -> n = ceil(work / (budget - maxTest))
which needs no fitted constant, no fixed point, and tracks the map rather
than a snapshot of it: a product carrying one heavy test gets the shards
that test forces, an evenly grained one gets none it does not need. A test
at or above the budget is called out on its own — no split can hold the
target then, so size by work alone instead of buying shards that cannot
help.
Against the current map this sizes the split products at 22 shards where
they run 27 today, and stops splitting signals, whose whole suite fits one
shard.
Claude-Session: https://claude.ai/code/session_01EJ1y3UzXR1BKtukE886ks9
…hard-sizing-factors
The drift check compares the depot shadows against canonical, so the legs loop and the untracked-map guard have to land in both. Claude-Session: https://claude.ai/code/session_01EJ1y3UzXR1BKtukE886ks9
…hard-sizing-factors
Review of the previous commit found the drift fallback still assumed the previous map is always on disk. Tolerating a cache miss in "Set the previous map aside" opened a path where /tmp/previous_durations does not exist, and the fallback's jq then aborts the whole processing step under bash -e, so Core, Temporal and Dagster never publish either. Losing the product entries for one refresh is the smaller failure, so fall back to an empty slice and keep the rest. A product test job now refuses to pass when its matrix entry carries no legs. An unset or malformed entry left the loop unentered and the job green having run no tests, which the single-command form could not do, and the rollup gate only reads this step. Three comments were left describing behaviour the code no longer has: the split path claiming a safety factor it no longer applies, a restore step claiming a cache miss leaves a checked-out file, and a packing note claiming optimal_chunks leaves the last shard lightest. The algorithm splits its heaviest group to reach the requested count, so that last claim was never true; the packing is sound because work/shards + maxTest bounds every shard, which the comment now says instead. Claude-Session: https://claude.ai/code/session_01EJ1y3UzXR1BKtukE886ks9
The mean-plus-one-test bound stops being informative once a single test eats most of a shard's budget: the denominator collapses and the count runs to the cap. A product with 321 seconds of work and one 319-second test asked for 50 shards where 3 hold the target. Below a quarter of the budget, size by work and add the one shard that carries the heavy test. The bucket factor's comment described the shared factor the sizing used before, which is history rather than a reason and goes stale as the model moves. It now states the invariant alone: the bucket factor covers error in the recorded durations, and the split path derives its own headroom. Claude-Session: https://claude.ai/code/session_01EJ1y3UzXR1BKtukE886ks9
A workflow edit reaches every open PR the moment it merges, while a change to the script beside it only arrives when the branch rebases. Reading matrix.legs and nothing else made the new workflow require a key those branches cannot have, and the guard added with it turned that into a hard failure before any test ran. The workflow now normalizes a missing legs value into a single leg built from the flat filters and pytest_args pair, so an unrebased branch runs the invocation its own turbo-discover planned. The script keeps that pair beside the leg on every entry one invocation can express; an entry with several legs has no such form, and by the time one exists the workflow reading it is the new one. The guard stays for the case where neither shape is present, which would pass the job having run no tests. Claude-Session: https://claude.ai/code/session_01EJ1y3UzXR1BKtukE886ks9
Sizing read a product's longest test and assumed the rest could pack around it. That holds for one heavy test and breaks for several: ten tests just under the budget were sized at nine shards, so two of them shared a chunk and ran to twice the target. Read the distribution instead. Tests above half a shard's budget cannot pair with each other, so they are counted rather than summed and set a floor no packing goes below. The remainder is at most half a budget per test, so a contiguous chunk of it runs at most one of them past its mean, which leaves n = ceil(lightWork / (budget - maxLight)). That denominator cannot fall below half the budget, so the count no longer runs to the cap when one test sits just under the budget either. Against the current map no product carries a test that large, so the real shard counts do not move. Claude-Session: https://claude.ai/code/session_01EJ1y3UzXR1BKtukE886ks9
Sizing counted a heavy test as taking a shard and left the rest to pack around it, but the cuts are contiguous: a heavy test between light tests divides the light run instead of lifting out of it. Ordered durations of 53, 301 and 133 seconds sized at two shards, and either cut leaves a chunk of 354 or 434 seconds against a 320-second budget. H heavy tests leave at most H + 1 light runs and each run rounds up on its own, so the light side can cost H shards beyond its own bound. Charge that whenever any light work exists. This is the worst case rather than the actual one, because the sizer reads the map and not collection order, and it only costs shards on a product holding a test above half the budget. Against the current map no product holds one, so the real shard counts do not move. The dedicated-bucket comment kept a record of why batch-exports was once listed. That is operational detail with a shelf life; only the condition for belonging in the set stays. Claude-Session: https://claude.ai/code/session_01EJ1y3UzXR1BKtukE886ks9
The two billed replay meters keyed on $snapshot_source and $lib, both of which arrive from the client unvalidated. Combinations outside the expected set matched neither meter. Web is now the catch-all for the source, and the SDK no longer takes part in the mobile meter, so the two partition every session.
Standing in an empty products slice when the cache missed let the refresh succeed and publish. That map becomes the newest cache entry and the latest successful artifact, so it shadows the older valid one and every consumer drops to the file-count estimate, under-sharding the fixture-heavy products until a later refresh lands. Fail the refresh instead and leave the older map newest. Reaching that needs both a cache miss and a Products slice that fails its drift check, unlike the unconditional checkout this branch started from. Shard sizing also charged for a fragmentation the suite may not have, and the charge could ask for more shards than the product has tests. A shard past that point collects nothing and spends a runner without shortening the critical path, so the count is capped at the test count. Claude-Session: https://claude.ai/code/session_01EJ1y3UzXR1BKtukE886ks9
The floor ran after the cap and undid it, so a product holding one test that overruns the budget planned two jobs. The second is guaranteed to collect nothing, and no split shortens the first, so cap the floor itself. The stale fallback also dropped the recorded heavy tests and re-estimated everything as five-second light work. Those recordings are measurements even where coverage is poor, and a test above half the budget holds a shard whatever the file count says. Keep them, and treat only the guessed remainder as light. Claude-Session: https://claude.ai/code/session_01EJ1y3UzXR1BKtukE886ks9
2 updated Run: 4591d94f-63cd-4f14-b77b-0701f885d6ba Co-authored-by: hpouillot <3455883+hpouillot@users.noreply.github.com>
The Person-table entry said `PERSON_TABLE_NAME` is not in the code. It is: #41620 merged from the same window and carried the setting to master, where `Person.Meta.db_table` reads it. The entry steered readers away from a switch that already exists. What did not land is the test setup and dual reads around it, so the entry stays and now says that. The xdist entry drew a 3-minute conclusion from a 6-minute measurement. The closing comment on #38927 reports ~15 min to ~9 min. The Blacksmith entry paraphrased a conclusion that lives only in an internal report. This repo is public, so the entry now carries the outcome the PRs show and stops there. Sparse checkout was labeled `rejected`, which this file defines as built and measured. Nobody reviewed that PR and the stale bot closed it, so `abandoned` is the verdict the taxonomy already has for it. Pointers went only to five CI skills, so a migration, endpoint, isolation, or stacking proposal never saw the sections written for it. Four more skills get the same one-line pointer. Claude-Session: https://claude.ai/code/session_011D2GDLMQGPxQLEkHxevuRs
trunk-io
Bot
deleted the
trunk-merge/pr-83663/efc82b1c-07a5-49eb-a7c7-354a9f6f924b
branch
August 27, 2026 12:14
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This pull request was created and is being managed by Trunk Merge.
This pull request is based on the master branch at SHA 7eced17f1684d6461a693c4621acaa75336840e9.
See more details about each PR in the batch here:
When CI completes, this pull request will be closed automatically.
Pull Requests Being Tested
This pull request is testing a batch with the changes from pull requests 83663 and 89755 - batching documentation.
Dependencies
This pull request depends on the changes from pull requests 89945, 89958, 90004, 84558, and 90010.