Skip to content

test(openapi): read the real documents from the corpus, and sweep all three vendors - #132

Merged
ShocOne merged 1 commit into
mainfrom
test/corpus-spec-tests
Aug 7, 2026
Merged

test(openapi): read the real documents from the corpus, and sweep all three vendors#132
ShocOne merged 1 commit into
mainfrom
test/corpus-spec-tests

Conversation

@ShocOne

@ShocOne ShocOne commented Aug 7, 2026

Copy link
Copy Markdown
Member

PR 2 of the artefact migration. Moves the spec-dependent tests in internal/ onto the corpus, and finds that two of them have never run.

Two tests that have always skipped

TestUnit_Discover_AgainstTheCommittedSpecification and TestUnit_Infer_AgainstTheCommittedSpecification both did this:

path := filepath.Join("..", "..", "..", "openapi", "thousandeyes", "7.0.97-…", "api.yaml")
if _, err := os.Stat(path); os.IsNotExist(err) {
    t.Skipf("the pinned snapshot is not present at %s", path)
}

Three parent hops from internal/openapi/ resolves above the repository. The path has never existed, so both tests have skipped silently and reported PASS since the day they were written:

=== RUN   TestUnit_Discover_AgainstTheCommittedSpecification
    discover_test.go:294: the pinned snapshot is not present at ../../../openapi/…
--- SKIP

The os.Stat guard was meant to be helpful when the snapshot was absent. What it did was hide a typo indefinitely — the failure mode of every skip nobody counts. Reading through the corpus removes both the hand-written path and the reason to guard it.

Both pass on their first real execution, against 7.0.99 rather than the 7.0.97 they named. What they assert about tag's operations holds across those versions, so nothing was papering over a real disagreement — but that is now something the repo knows rather than assumes.

The cross-vendor sweep

The part that widens coverage rather than preserving it. Every ingestion defect this generator has had was found by a second vendor's document disagreeing with the first, never by a fixture written alongside the code it exercises — Jamf Pro alone produced six.

Discovery and inference now run over all three pinned documents, asserting what must hold whatever the vendor did:

thousandeyes: 34 resource(s) inferred, 0 failed, 86 named refusal(s)
jamfpro:      59 resource(s) inferred, 0 failed,  9 named refusal(s)
github:       40 resource(s) inferred, 0 failed, 62 named refusal(s)

Determinism is the load-bearing one: discovery walks maps, Go randomises map iteration, and an ordering bug is invisible in a single run — it surfaces later as a blueprint that differs between two identical generations. Also asserted: scale matching the lock, a stated reason on every classification, and a non-empty message on every dropped field, because a note with no text is a silent drop wearing a refusal's clothes.

The identifier test pins the disagreement that cost the most to find:

thousandeyes: id attribute kinds [string]
jamfpro:      id attribute kinds [int64 string]

so a future simplification that re-hardcodes one shape fails on the other.

Two corrections to what landed in #131

internal/corpus no longer imports internal/openapi. That package's tests are in-package and among the corpus's most important consumers, so the import was a cycle — and would have forced them back onto the relative paths that caused this whole problem. The parser is now installed as a hook by the binary, which has no such constraint.

The cache default was a real defect, not a preference. It was .tfpfgen/cache/corpus, relative. go test runs every package in its own directory, so one suite run scattered a copy of every document through the tree, into package directories that the root-anchored .gitignore pattern never matches. I caught it because git add -A staged 451,614 insertions — 19 MB of specifications, into the commit whose entire purpose is removing artefacts from this repository.

It now defaults to the user cache directory (~/Library/Caches/tfpfgen/corpus), which is absolute and outside any checkout. A test asserts it is not relative and not beneath the working directory, and a **/.tfpfgen/cache/ pattern backs that up — the mistake is easy to make again and expensive to notice.

Deletion

internal/snapshot's committed-snapshot test is deleted rather than repointed. Its subject was the artefact, not the mechanism, and the artefact is leaving. The mechanism stays covered hermetically by VerifyCatchesAnEditedSnapshot, VerifyToleratesMissingChecksum and the ordering tests beside it — and the corpus applies the same two gates (checksum against metadata, digest against the lock) on every materialisation.

Verification

  • go build, go vet, go test ./..., gofumpt all clean.
  • After a full suite run, find . -name .tfpfgen outside pilot/ returns nothing.
  • Staged diff is 353 insertions.

🤖 Generated with Claude Code

… three vendors

Two tests claimed to check discovery and inference against the real ThousandEyes
document. Neither has ever run. Both built their path with three parent hops
instead of two, which resolves above the repository, and both guarded that path
with an os.Stat and a t.Skipf -- so they skipped silently, reported PASS, and
have done since they were written.

The guard was meant to be helpful when the snapshot was absent. What it did was
hide a typo indefinitely, which is the failure mode of every skip nobody counts.
Reading through the corpus removes the hand-written relative path and the reason
to guard it: a document that cannot be obtained skips or fails by one policy
decided in one place, and a document that is present but wrong fails everywhere.

Both pass on their first real execution, against 7.0.99 rather than the 7.0.97
they named. What they assert about tag's operations holds across those versions,
so nothing was papering over a real disagreement -- but that is now something
this repository knows rather than something it assumed.

internal/snapshot's committed-snapshot test is deleted rather than repointed.
Its subject was the artefact, not the mechanism, and the artefact is leaving;
the mechanism is covered hermetically by the Verify and ordering tests beside
it, and the corpus applies the same two gates on every materialisation.

The cross-vendor sweep widens coverage rather than preserving it. Every
ingestion defect this generator has had was found by a second vendor disagreeing
with the first, never by a fixture written alongside the code it exercises, and
Jamf Pro alone produced six. Discovery and inference now run over all three
pinned documents, asserting what must hold whatever the vendor did: determinism
across repeated discovery, since Go randomises map iteration and an ordering bug
is otherwise invisible until it surfaces as a blueprint that differs between two
identical generations; scale matching the lock; a stated reason on every
classification; and a non-empty message on every dropped field, because a note
with no text is a silent drop wearing a refusal's clothes. It reports 34
resources from ThousandEyes with 86 named refusals, 59 from Jamf Pro with 9, and
40 from GitHub with 62.

The identifier test pins the disagreement that cost the most to find: Jamf Pro
yields both int64 and string identifiers where ThousandEyes yields only string,
so a future simplification that re-hardcodes one shape fails on the other.

Two corrections to what landed in #131.

internal/corpus no longer imports internal/openapi. That package's tests are
in-package and among the corpus's most important consumers, so the import was a
cycle that would have forced them back onto the relative paths which caused all
this. The parser is installed as a hook by the binary, which has no such
constraint.

The cache defaulted to a relative path, and that is a genuine defect rather than
a preference. `go test` runs every package in its own directory, so one suite
run scattered a copy of every document through the tree, in package directories
no root-anchored .gitignore pattern reaches -- it put 19 MB of fetched
specifications into a staged commit whose entire purpose was removing artefacts
from this repository. It now defaults to the user cache directory, which is
absolute and outside any checkout. A test asserts that and a .gitignore pattern
backs it up, because the mistake is easy to make again and expensive to notice.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@ShocOne
ShocOne merged commit 00dcab3 into main Aug 7, 2026
10 of 12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant