feat: an acceptance test replays a request the API took - #119
Merged
ShocOne merged 1 commit intoAug 26, 2026
Conversation
Every generated acceptance test failed at its first step, and the reason was the same one every time in a different field: the configuration was derived from the document rather than taken from the API. The probe already gets creates accepted. It then threw the body away — the accepted bodies lived in memory only long enough to diff variants — and generation went back to the document and invented values again. So a fixture sent tfpfgen-test-icon where the API only takes LABEL, and each such field had to be found and fixed one at a time. The probe now records what it got accepted, request and response, to audit/bodies/<entity>.bodies.json, and the acceptance configurations are built from that. A configuration is now a request the API demonstrably took rather than a reconstruction resembling one. The unit configurations stay derived, because their mocks are built from the same derivation and the two must not disagree. Bracketing the create are two searches. Additive for the minimal: the document's required fields are only a hypothesis, so a refused create adds one field at a time until the API answers 2xx, which is the first thing that makes an entity declaring nothing required creatable at all. Subtractive for the maximal: what the API objects to is dropped until it takes the rest. Both bounded per entity; a refused create makes no object, so a search costs requests rather than debris. The response decides what a configuration may hold. A property the API accepts and never returns cannot live in one — terraform reads a value that never comes back as the provider losing it — so it is dropped and the reason written into the file. Names that reach a live API carry a per-run suffix from a random_string the configuration declares, so a re-run never collides with what the last one left behind. Only invented names take it: a value the document supplied is one the API accepts, and appending to it could make it invalid. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
ShocOne
deleted the
feat/an-acceptance-test-replays-a-request-the-api-took
branch
August 26, 2026 11:54
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.
Every generated acceptance test failed at its first step. The reason was the same one every time, in a different field: the configuration was derived from the document rather than taken from the API.
The probe already gets creates accepted. It then threw the body away — accepted bodies lived in memory only long enough to diff variants — and generation went back to the document and invented values again. So a fixture sent
tfpfgen-test-iconwhere ThousandEyes only takesLABEL, and each such field had to be found and fixed one at a time.What changed
The probe records what it got accepted, request and response, to
audit/bodies/<entity>.bodies.json:{ "entity": "tag", "minimal": { "status": 201, "request": {"accessType":"all","key":"branch","objectType":"test","type":"static","value":"sfo"} } }Acceptance configurations are built from that. A configuration is now a request the API demonstrably took, rather than a reconstruction resembling one. Unit configurations stay derived — their mocks are built from the same derivation, and the two must not disagree.
Two searches bracket the create. Additive for the minimal: the document's
requiredis only a hypothesis, so a refused create adds one field at a time until the API answers 2xx. This is the first thing that makes an entity declaring nothing required creatable at all. Subtractive for the maximal: what the API objects to is dropped until it takes the rest. Both bounded per entity; a refused create makes no object, so a search costs requests rather than debris.The response decides what a configuration may hold. A property the API accepts and never returns cannot live in one — terraform reads a value that never comes back as the provider losing it — so it is dropped and the reason written into the file:
Live names carry a per-run suffix from a
random_stringthe configuration declares, so a re-run never collides with what the last one left behind. Only invented names take it: a document-supplied value is one the API accepts, and appending to it could make it invalid.Two workarounds removed
Both were mine, from chasing these failures field by field:
x-tfpfgen-server-defaultas an input value. A server default is what you get back when you omit a field; sending it back is a category error that happened to work foricon: LABEL.The four test assertions rewritten for that mapper change are restored to their original form.
Measured
tags/v1/tagpasses all three steps of the acceptance suite — create minimal, import verify, update to maximal — on a replayed body.make checkgreen at 90.7%; both pilot trees regenerate and pass postcheck.Known, not fixed here
No maximal is recorded yet for any entity.
runCreateMinimalleaves its object alive, thenrunCreateMaximaltries to create a second one and the API refuses a duplicate. The reduction runs correctly — it strips back to the protected minimal — but cannot reach a 2xx while the first object exists. That ordering problem is pre-existing and is the next branch.🤖 Generated with Claude Code