feat(upload): address failing tests by test-case GUID in collection links - #1196
Open
max-trunk wants to merge 1 commit into
Open
feat(upload): address failing tests by test-case GUID in collection links#1196max-trunk wants to merge 1 commit into
max-trunk wants to merge 1 commit into
Conversation
…inks The report table's per-test links now use the ADR-0019 GUID — a UUIDv8 hash of `(test_collection_id, repo_id, test_case_id)` — addressing the canonical `collections/<short_id>/tests/<guid>` page directly instead of the `/t/<id>` short link the webapp has to resolve a repo for and redirect. The two server-owned legs of the tuple come from `createBundleUpload`, which now returns `repoId` and `testCollectionId` (trunk-io/trunk#33761). Both are `Option` with `serde(default)`: a server predating that PR sends neither, `testCollectionId` is absent under maintenance mode and for orgs with the receipt-inserts flag off, and the CLI must keep working against all of them. Every way the GUID can be unavailable funnels through one decision point in `url_for_test_case` and falls back to today's link: - no collection short id, or links hidden - the server returned no ids - `test_case.id` is not a UUID — a report-supplied id passes through verbatim (RSpec emits `trunk:<id>-<location>`), and hashing one would mint a well-formed GUID that addresses nothing `gen_test_case_guid` is the same compiled `context` crate ingest runs, so there is no second implementation of the frozen hash. The URL test pins ADR-0019's first golden vector rather than recomputing the hash, so a drift in either the contract or the URL shape fails the build. The pre-upload `log_failure` lane still prints the short link: it runs before `createBundleUpload`, so the ids do not exist yet. Hoisting that call is the follow-up. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Merging to
After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here |
TylerJang27
approved these changes
Sep 10, 2026
TylerJang27
left a comment
Collaborator
There was a problem hiding this comment.
LGTM. Forcing a CI rerun to see it in practice
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.
What this changes
The report table's per-test links address the test case by its ADR-0019 GUID — a UUIDv8 hash of
(test_collection_id, repo_id, test_case_id)— instead of the/t/{id}short link the webapp has to resolve a repo for and redirect.No
?repo=— the GUID resolves the whole identity tuple, so there is nothing for the webapp to look up. Same shape of win as #1169 took for upload links.Where the two server-owned ids come from
createBundleUploadnow returnsrepoIdandtestCollectionId(trunk-io/trunk#33761). Both land onCreateBundleUploadResponseand are threaded to the report table — deliberately not throughBundleMetaBaseProps, since ingest does not need them and that would churn the bundle schema.gen_test_case_guidis the same compiledcontextcrate ingest runs, so there is no second implementation of the frozen hash.Blocking on the webapp route
This needs the in-flight
collections/{shortId}/tests/{guid}route to land before it ships. The path shape is assumed here and pinned in oneformat!plus one golden test, so correcting it is a two-line change if it differs.One request for whoever builds it: an unknown GUID should render an empty state, not a hard 404 — matching what
tests/[testKey]already does viaCollectionNotFoundError. See the next section for why that matters.Why this might not be as clean as it looks
FailedTestsExtractorderivestest_case.idfrom the raw JUnit tree, while ingest derivestest_case_idfrom the normalizedinternal.bin— so when a report putsfileon<testsuite>rather than<testcase>, the two disagree and we hash the wrong tuple. That is pre-existing (today's short link is equally wrong in that case) and the fix belongs in its own PR, but it is the reason the empty-state request above is not cosmetic.repoIdisOptioneven though the server guarantees it. Deliberate: serde would hard-fail the wholecreateBundleUploaddeserialization — killing the upload — over a field that only decorates a link. A rollback, a canary, or the public-api JSON schema lagging the gRPC change all produce that.testCollectionIdhas no choice: the proto declares itoptionaland the server returns null under maintenance mode or with the receipt-inserts flag off.Learn morelines still print the short link —createBundleUploadruns after them, so one--verboserun shows two URL shapes for the same test. Reordering the calls to fix it was tried in refactor(upload): resolve the upload id before the quarantine step #1197 and closed: it shiftsupload_started_atand the receipt→upload window, which is a bad trade for something only visible under-v(a default run shows the report table, which is fully on the GUID here). If it ever matters, the shape is to echo the two ids on/metrics/getQuarantineConfigtoo — no reordering. Reasoning in refactor(upload): resolve the upload id before the quarantine step #1197.Fallback behaviour
Every way the GUID can be unavailable funnels through one decision point in
url_for_test_caseand degrades to today's link: no collection short id, links hidden,--dry-run, a server that sent no ids, or atest_case.idthat is not a UUID (RSpec emitstrunk:<id>-<location>, and hashing a non-UUID would mint a valid-looking id addressing nothing).Implementation notes
TestCaseGuidScopebundles the two server ids rather than taking twoOption<&str>params, so "both ids or neither" is unrepresentable — the server cannot produce one without the other.uuidbecomes a direct dep ofapi; it was already in the lock, so the lock diff is one line.render_test_tablenow usesself.api_addressinstead of the globalget_api_host(), matchingcollection_upload_urlright above it.Testing
api: 25 passed — golden GUID vector, plus fallbacks for an unparseable server id and the repo-scoped pathtrunk-analytics-cli --test upload: 58 passed, including a new mock-server case that returns no ids and asserts the full short-link form (?repo=included) comes back--test test: 13,--test validate: 9, cli lib: 23,test_utils: 1cargo clippyadds no warnings (304 before and after);cargo fmtclean for every file touched — the one pre-existing diff incontext/src/junit/parser.rsis onmaintoo🤖 Generated with Claude Code