fix: a probe invents the name it must be able to clean up - #123
Merged
ShocOne merged 1 commit intoAug 26, 2026
Merged
Conversation
A name must be unique per run and must carry the prefix cleanup matches on, so the invented token now beats a declared example in both synthesis paths. An example is a value the API accepted once: an API that requires a name to be unique refuses it every run after, and the object the first run created under it carries no prefix, so the cleanup pass cannot see it and it stays in somebody's tenant for good. A field an enum, a format or a pattern constrains is left on the ordinary priority — the token satisfies none of those shapes. The plan and the strategized run change together: the live path synthesises from strategize, and a rule applied to one alone would mean the plan and the run disagreed about what they sent. nameBearing loses its duplicate with it, exported from the plan package the run already imports. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
ShocOne
deleted the
fix/a-probe-invents-the-name-it-must-be-able-to-clean-up
branch
August 26, 2026 14:17
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.
The defect
Both synthesis paths —
synth.valueininternal/audit/planandsynthValueininternal/audit/run— orderExampleahead of the name-bearing token. Only the type fallback ever reachesnameToken, so any name-bearing field whose schema declares an example is probed with the document's example.Two things follow, and the pilot shows both:
The API refuses it.
account_groupsent{"accountGroupName":"My testing account group"}— the document's example — and got:Cleanup cannot see what it created.
cleanup.gomatches live objects byaudit.name_prefix. An object created under a document example carries no prefix, so the prefix pass cannot match it and it stays in the tenant permanently.handoff.mdfilesaccount_groupunder "blockers that are not code" and says the leaked object needs org-admin to remove. It is code: the leak exists because the probe created the object under a name cleanup was never going to match.The fix
In both paths, a name-bearing field with no enum, format or pattern takes the invented token rather than the declared example. A field carrying one of those constraints is left on the ordinary priority — the token satisfies none of those shapes, so such a field is not one to invent a name for.
Both paths change together deliberately.
Rununconditionally strategizes when the document and config are present, so the live path synthesises fromstrategize; changing the plan alone would leave the plan and the run disagreeing about what they sent.nameBearingwas duplicated in both packages. It is now exported once frominternal/audit/plan, whichinternal/audit/runalready imports.Verification
make check(90.7% total;audit/plan93.2%,audit/run90.5%). Both new tests were confirmed to fail with the rule disabled.One test expectation had to be corrected while writing it, and the correction is a fact worth recording: a declared example already outranks an enum in the existing priority, so a name-bearing field carrying an enum falls through to the example rather than to the enum's first member. The comments say that rather than the tidier thing I first wrote.
What this does not do
It takes a probe re-run to show. No acceptance test changes from this PR alone — the recorded request bodies on disk were captured under the old rule. The already-leaked
account_groupobject still holds its name and still needs org-admin; this stops the next one.Note for CI
Two lint findings (
QF1001instrategy_test.go,unparamonreduceMaximal) are pre-existing onmainand are fixed in #121. They are untouched here to avoid a conflicting duplicate fix.🤖 Generated with Claude Code