Put a curated summary's companion contracts in the scene - #216
Open
shellygr wants to merge 8 commits into
Open
Conversation
A curated summary may reroute a library's calls to a companion of its own: OZ_BitMaps.spec sends BitMaps.get to OZ_BitMaps.get. CVL can only name a contract that is in the scene, and the scene is the files the conf lists, so copying the companion beside the spec never made it nameable. Any project whose methods match the bitmaps entry fails its warmup typecheck with "Variable `OZ_BitMaps` has not been declared". The base conf now carries an entry per top-level definition in each matched entry's additional_contracts, which is also what keeps them nameable when one file holds more than one. `curated_scene_contracts` lives in summary_resolver rather than beside its caller because setup_summaries exits at import time without an API key, and a unit test cannot import it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Contributor
Author
|
Tests are in Certora/Autosetup#148. |
That config exists to typecheck the summaries that were just set up, and it was built with an empty additional-contracts list, so a summary rerouting through a companion was typechecked against a scene the companion is missing from. It is the config a real run died in. Whether the run's own --additional-contracts belong there as well is still open, so the TODO's question stands; only the companions move. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A third place decides a conf's scene: the call-resolution path rewrites `files` from the main contract plus the additional contracts, which stripped the companions back out again and left the summary naming a contract that is no longer there. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The bundled OZ_BitMaps companion could never work. A reroute target must be an external library function, and every function in it was internal; and even made external, it declared its own copy of `struct BitMap`, which is a different type from the project's however identical it looks — parameter matching compares canonicalId, which names the file the type came from. So the companion is now a template, filled in per project with the project's own BitMaps.sol as the import and that library's pragma. Verified by hand first: with the companion internal the typechecker gives exactly the production error, and with it external and importing the project's own library it exits clean. Two adjacent gaps this uncovered, both general rather than BitMaps-specific: a file added to `files` needs its compiler_map entry or certoraRun rejects the conf as unmatched, and a companion shipped as a template is emitted under its untemplated name, which is the name the scene has to look for. The spec's ghosts now key on calledContract rather than currentContract, which is bound to the primary contract and so let two contracts holding a BitMap at the same slot alias each other's bits. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Every other entry in a conf is relative to the project root, and an absolute one bakes the build machine's layout into a file that travels with the run. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The prune pass drops an internal-method entry whose receiver is absent from the scene index, and that index is built from the project's own compilation — which happens before a curated companion joins the conf. So every OZ_BitMaps entry was commented out as "not in scene", leaving the reroute pointing at a companion whose bodies revert on every call: a green run that proved nothing, which is worse than the loud failure it replaced. The exemption is per receiver and covers only contracts that are genuinely in the conf and cannot be in an index that predates them. A receiver that is absent for the ordinary reason is still dropped. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The four `require(false)` bodies were a tripwire for "summarization failed". They guaranteed it instead: an unconditionally reverting body leaves nothing for the summary to attach to, so every BitMaps call reverted, and rules over a reverting call pass vacuously. The tripwire caused the failure it announced, and made it silent. Measured on a project that uses BitMaps, one variable changed: anchors callsAreReachable the four behavioural rules require(false) VIOLATED all SANITY_FAILED neutral VERIFIED all VERIFIED, none vacuous setThenGetIsTrue verifying non-vacuously is what settles it: with neutral bodies and no working summary, set stores nothing and get reads false, so that rule fails. It passes, so the ghost is doing the work. Neutral bodies also invert the failure mode. An unattached summary now shows up as a violated rule rather than a green vacuous one, and rule_sanity catches the rest. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
OZ_BitMaps.specsummarizesBitMapsby rerouting its calls to a companion library of its own,OZ_BitMaps. CVL can only name a contract that is in the scene, and the scene is the files the conf lists.copy_summaries_foldercopies the companion beside the spec and stops there, so nothing ever puts it in a conf.The result is that any project whose methods match the
bitmapsentry fails its warmup typecheck:bitmapsis the only entry infunction_summaries.jsonthat declaresadditional_contracts, and it has not changed since the package was imported from the AutoSetup repo, so I believe this has never worked. I hit it on a dev run whose main contract callsBitMaps.get/set/unset/setTo.The base conf now carries an entry per top-level definition in each matched entry's
additional_contracts. Per definition, not per file: a conf entry naming only the file puts just the stem-named contract in scene.Two things worth a reviewer's attention:
curated_scene_contractslives insummary_resolver.pyrather than next to its caller insetup_summaries.py, because that module callssys.exit(1)at import time when there is noANTHROPIC_API_KEYor.env, so a unit test cannot import it at all.copy_summaries_folderalready does for a missing bundled file. Happy to make it fatal instead.Tests in Certora/Autosetup#TBD (six cases: the conf entry, multiple definitions per file, a summary with no companion, nothing matched, an unknown key, and the uncopied-companion warning).
🤖 Generated with Claude Code
Folded in (was #219): make the reroute actually attach.
Putting the companion in the scene was necessary but not sufficient. Two more things stopped
OZ_BitMapsfrom doing anything:canonicalId, which is"<file resolved under .certora_sources>|<qualified name>". A bundled companion declares its own copy ofBitMaps.BitMap, and that is a different type from the project's however identical it looks. The companion is now generated per project from a template, importing the project's own copy of the library.require(false)tripwires. A body that always reverts leaves the summary nothing to attach to, so every call through it reverts and every rule over it passes vacuously. That reads as a green run. The bodies are neutral now.Two smaller ones, both fixed here: the host functions have to be
external, sinceDetectRerouteSummariesonly sees external library functions, and the summary entries have to survive the prune pass, which drops entries naming a contract that is not in the scene index. That index comes from the project's own compilation, which happens before the companion exists.Checked on a small project that uses BitMaps: every rule verifies under
rule_sanitybasic, and one of them is a baresatisfy, so a vacuous pass fails instead of looking like success. Tests are in the Autosetup PR.