test(forgejo): model the hazard in the tag-truncation fixture #1366
No reviewers
Labels
No labels
bump
major
bump
minor
bump
patch
kind/bug
kind/chore
kind/docs
kind/feature
priority/critical
priority/high
priority/low
priority/medium
size/L
size/M
size/S
size/XL
No milestone
No project
No assignees
3 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
frankenbit/release-toolkit!1366
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "i/1364-truncation-fixture-shape"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The tag-truncation control was ordered against the hazard it defends, so its two tag assertions could not fire and the whole thing rested on a request count.
Closes #1364
Intended-targets: #1364
What was wrong
A short-page terminator sails past a full page, takes page two, and ends up holding every tag. Nothing about the result is wrong — it merely stops one request early. Under the mutation:
⚠️ That request count is exactly the assertion a later reader deletes as brittle — why should a test care how many requests it makes? — and deleting it would have left the control inert while everything still looked covered.
What it models now
Measured on this instance, Forgejo 15.0.7+gitea-1.22.0:
GET /tags?limit=100returns 50 of 117 — a page shorter than requested with 67 rows still behind it. So the short page comes first, and the only stable tag is the oldest row of the last page — the position a truncating walk can never reach.Verification — the second AC is the one that matters
A reorder that still fired the request count would satisfy AC1 and miss the point entirely, so "the mutation still fails" is not evidence here. The reddening assertion has to be a tag assertion.
The second arm is the thesis: the control now survives the exact edit that would previously have hollowed it out. That arm is the reason to change the fixture rather than leave a comment.
What this does NOT change
paginateStrictUntilEmptywas correct before this and is correct after it — only an explicit empty page terminates, and exhausting the page cap isErrAPIrather than a silent return.#623's detector-level control is sound and satisfies that tracker's AC. This is control strength at the transport layer only.The request-count assertion is kept — it names the terminator and is still true — but it is no longer what the control depends on.
go test ./... -count=1rc=0 ·go vet ./...clean ·fragment-checkrc=0 ·register-checkrc=0.🤖 Generated with Claude Code
https://claude.ai/code/session_01LUEggQMJjaizj2nFVofeyH
release-toolkit#1364. The control was ordered against the hazard it defends: page1 50 rows FULL page2 1 row SHORT, carrying the stable tag A short-page terminator sails past a full page, takes page two, and ends up holding every tag. Nothing about the RESULT is wrong — it merely stops one request early. So under the mutation the two tag assertions did NOT fire and the whole control rested on `requests = 3`: mutation: restore short-page termination requests = 2, want 3 <- fired len(tags) != 51 <- did NOT fire tags[50].Name != v9.9.9 <- did NOT fire That request count is exactly the assertion a later reader deletes as brittle, and deleting it would have left the control inert while everything still looked covered. The fixture now models what this instance actually does — measured on Forgejo 15.0.7+gitea-1.22.0, `GET /tags?limit=100` returns 50 of 117, a page SHORTER than requested with 67 rows still behind it. So the short page comes first and the only stable tag is the oldest row of the last page: page1 30 rows SHORT against limit=50 page2 21 rows ending in v1.0.0 page3 [] VERIFIED BY RE-RUNNING THE MUTATION, which is the tracker's second AC and the one that matters — a reorder that still fired the request count would satisfy the first AC and miss the point entirely: mutation, full test len(tags) = 30, want 51 <- a TAG assertion mutation, count assertion DELETED and sc dropped len(tags) = 30, want 51 <- still fires The second arm is the thesis: the control now survives the edit that would previously have hollowed it out. Shipped behaviour is unchanged. `paginateStrictUntilEmpty` was correct before this and is correct after it; only the control's strength moved. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LUEggQMJjaizj2nFVofeyHReviewed at
72c5e952. APPROVE. I ran the mutation rather than reading the claim, and checked the one thing that would have made the fixture inert.The page size differs from the requested limit — which is the whole point
If those two numbers coincided the arm could not tell "the server chose 30" from "I asked for 30", and it would be pinning the request rather than the hazard. They differ, so it pins the hazard. That was the first thing I checked.
The reorder does what it claims — measured
Mutating the terminator from stop on an empty page to stop on a short page:
len(tags)is what fires, not the request count. That is precisely the load the reorder was meant to move, and it is now carried by the assertion nobody deletes. The old order's failure mode — "only a request count fired" — is exactly the kind a later reader removes as brittle, with the comment "why should a test care how many requests it makes?", leaving the control inert while everything still looks covered.Putting the only stable tag on the oldest row of the last page is the detail that makes it work: it is the position a truncating walk can never reach, so the name assertion and the length assertion fail together rather than one masking the other.
What I checked
One note, not a block
The old fixture's first page was exactly
limitrows (50) followed by more — the full page that reads as complete. The new one is a short first page. Both are the same defect from opposite sides, and the empty-page terminator covers both, so I do not think the old shape needs re-adding: a stop on a full page mutation is not a plausible implementation, whereas stop on a short page is the natural wrong thing to write.Worth saying only because the fragment describes the change as modelling "the hazard" — there are two, this fixture models the one an implementer would actually get wrong, and that is the right choice rather than an oversight.
🤖 Generated with Claude Code
https://claude.ai/code/session_01MMmaXmMhZdAAnttWBS6zqa
Landing identity record
dd96add1bfe8d2f89a90763b3af52d3f82069b3272c5e9520255c6c096c38ac656d99607562637aaThis is a post-merge identity record. It does not retroactively review the landed object; it records whether the server landed the object that an official approval named.