Skip to content

fix(clone): proof * [-tag] should force (realize) untagged axioms - #1098

Open
namasikanam wants to merge 1 commit into
mainfrom
fix/clone-proofstar-tags
Open

fix(clone): proof * [-tag] should force (realize) untagged axioms#1098
namasikanam wants to merge 1 commit into
mainfrom
fix/clone-proofstar-tags

Conversation

@namasikanam

@namasikanam namasikanam commented Aug 24, 2026

Copy link
Copy Markdown
Collaborator

Summary

clone ... proof * [-tag]. leaves untagged axioms as they are. This lets a clone
instantiate a false instance of an untagged axiom (e.g. FinType.enum_spec) and derive
false (see the example below).

require import AllCore List FinType.


clone FinType as F with
  type t <- int,
  op enum <- [0]
  proof * [-dummy] by smt().

lemma bad : false.
proof.
have h := F.enum_spec 1.                               (* forall x, count (pred1 x) [0] = 1 *)
have : count (pred1 1) [0] = 1 by apply h.     (* count (pred1 1) [0] = 0, not 1    *)
by rewrite /count /pred1 /=.
qed.

Root cause

check_evtags (src/ecTheoryReplay.ml) decides whether an axiom is forced by mapping the
directive's tag test over the axiom's own tag list src. For an untagged axiom src = [],
List.mem true (List.map _ []) = false, so it is never forced — and the correct default
(dfl) is never consulted.

Fix (src/ecTheoryReplay.ml)

Rewrite the tag-matching so the directive is folded starting from the default dfl, testing
membership of each directive tag in the axiom's src. Untagged axioms now correctly fall
back to the default (forced), while explicit [-tag] exclusions still apply to tagged
axioms.

Test

tests/clone-proofstar-tagdrop.ec (must-fail): a proof * [-dummy] clone that previously
dropped an untagged axiom is now rejected. Contrast: the no-bracket proof * form already
rejected, confirming this was a genuine drop rather than the by-design "clone assumes its
axioms" behaviour.

@namasikanam
namasikanam force-pushed the fix/clone-proofstar-tags branch from 36150f0 to 70586cc Compare August 24, 2026 10:02
@strub

strub commented Aug 24, 2026

Copy link
Copy Markdown
Member

I don't understand the problem here:

require import AllCore.

theory T.
  axiom A : false.
end T.

clone T as U proof * [foo].

print U.

gives:

theory U.
  (* import *) axiom A: false.
end U.

@oskgo

oskgo commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Yeah. This one isn't a soundness issue. I would consider it unexpected that proof * [-foo] excludes not just axioms tagged foo but also those without a tag though.

@namasikanam

Copy link
Copy Markdown
Collaborator Author

I'm trying to understand and getting confused. What are the expected behavior of clone ... proof * [tag] and clone ... proof * [-tag]?

@strub

strub commented Aug 26, 2026

Copy link
Copy Markdown
Member

I'm trying to understand and getting confused. What are the expected behavior of clone ... proof * [tag] and clone ... proof * [-tag]?

  • proof * [tag] -> realize the axioms tagged with foo
  • proof * [-tag] -> realize the axioms not tagged with foo

As @oskgo said, with your PR, proof * [-tag] remove the untagged lemmas from the realization set.

Closing this PR. This is not a soundness issue and this is the desired behavior.

@strub strub closed this Aug 26, 2026
@oskgo

oskgo commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

@strub It's the other way around. The current behaviour is that proof * [-tag] excludes the untagged axioms from the realization set. The PR changes it so only the axioms tagged by tag are removed.

@oskgo oskgo reopened this Aug 26, 2026
@fdupress fdupress changed the title fix(clone): proof * [tag] must not drop untagged axioms fix(clone): proof * [-tag] should not drop untagged axioms Aug 26, 2026
@fdupress

Copy link
Copy Markdown
Member

I fixed the title, but I'll leave it to @namasikanam to fix the description. Please do check those for accuracy—it helps with triaging and review.

This is still not a logical soundness bug, although it may be a "perceptual soundness" issue: the axioms still exist, they are simply not discharged when a reader/reviewer might expect them to be.

@strub

strub commented Aug 26, 2026

Copy link
Copy Markdown
Member

Ah yes I tested with this PR binary.

@namasikanam
namasikanam force-pushed the fix/clone-proofstar-tags branch from 70586cc to c7f0721 Compare August 28, 2026 12:59
`check_evtags` (`ecTheoryReplay.ml`) decided whether an axiom was forced by a
bracketed `proof * [-tag]` directive by mapping the directive's tag test over
the *axiom's own* tag list `src`. For an untagged axiom `src = []`, the test
`List.mem true (List.map _ [])` is `false`, so the axiom was silently NOT
forced and the correct default `dfl` was never consulted. A clone could then
assume an untagged axiom without proof (e.g. instantiate `FinType.enum_spec`
falsely and derive `false`).

Fold the directive tags starting from the default `dfl`, testing membership of
each directive tag in the axiom's `src`. Untagged axioms now fall back to the
default (forced when the bracket list is exclusion-only); positive include
lists (`proof * [tag]`) are unaffected, since their default is not-forced.

Regression: tests/clone-proofstar-tagdrop.ec (asserts the bracketed clone that
dropped the untagged axiom now fails, via the `fail` idiom).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@namasikanam
namasikanam force-pushed the fix/clone-proofstar-tags branch from c7f0721 to 1848724 Compare August 28, 2026 13:11
@namasikanam namasikanam changed the title fix(clone): proof * [-tag] should not drop untagged axioms fix(clone): proof * [-tag] should force (realize) untagged axioms Aug 28, 2026
@namasikanam

namasikanam commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator Author

I've fixed the PR description and commit message. I think it's indeed a soundness issue. Look at the example in the PR description.

@oskgo

oskgo commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Even though it looks like you have an axiom-free proof of false here, you don't actually have one.

In your example if you do print axiom or print the entire theory you'll see that the false enum_spec axiom is still here. It would be a soundness issue if it turned the axiom into a lemma or removed it without requiring you to prove it during the clone.

I like François' term of "perceptual soundness". The logic is still solid, but the presentation is not.

@fdupress

Copy link
Copy Markdown
Member

Just to reinforce the point, the following is not a soundness issue.

axiom toto: false.

lemma titi: false by exact: toto.

The example in your PR description is that, with a rug placed over the axiom toto bit. But we already have mechanisms to lift that kind of rugs. (print axiom, for one.)

I do dislike the fact that the current behaviour is not what one would expect, which means that we currently expect the user to use print axiom to be convinced that we didn't hide anything. But that is not a soundness issue.

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.

4 participants