Loading
Commits on Source 4
-
Matt Cockayne authored
-
Matt Cockayne authored
-
Spec 0009 D5. The refusal contract was prose, and prose is what produced the state the spec was raised for: one provider honoured ErrReleaseNotFound and four did not. A rule in a document is followed by whoever read the document; a rule in the shared harness is inherited by every provider that runs it, including ones nobody has written yet. Two checks, at two different seams: - MissingTag now drives an assertion rather than only a log line. The field was documented as optional and consumed only by the logging check, so the narrowest and most-broken half of the contract — a tag that does not resolve — had no mechanical check at all. - NewProviderAt is a new optional constructor that builds the provider against a URL the harness supplies. Three of the five refusals cannot be provoked from a fixture, because nothing makes a healthy forge rate-limit a test, so the harness stands up a server that answers with one status and set of headers and checks what the provider made of it. Omitting it leaves the mapping unverified rather than assumed satisfied, which is the protocol the rest of the config already uses. The 404 case accepts either not-found sentinel. Which one is right depends on what the provider addressed, and that is a per-provider decision the spec settled (D4) rather than a mapping error: GitLab reports a 404 from its release listing as ErrNotFound because a missing project is what that status means there, and Bitbucket Downloads has no release concept to miss. A 404 carrying neither is the defect, and that is what fails. Every case is falsified against a mutant that gets exactly that case wrong and nothing else, because a check that passes with ErrForbidden substituted for ErrRateLimited is not evidence. The mutants are deliberately close to correct: confusing two neighbouring refusals is the realistic defect, and it is the one with a consequence — a caller told "forbidden" has no reason to back off, and one that treats forbidden as a credential problem re-resolves, aiming a burst of resolutions at an API that is already refusing. The server fault is checked with a 501 rather than a 500. Every SDK in this family retries a 500 with backoff, and a fixture answering 500 to every request pays that in full — twelve seconds, measured against go-gitlab — before the check can look at the error. 501 is treated as final by those same retry policies and makes the same point. Documentation caught up with the sentinels while it was open: the three refusal sentinels shipped undocumented, and the errors reference still told callers not to rely on ErrReleaseNotFound across the first-party set. -
Matt Cockayne authored