Case 853
The anchor bound to one alternative
the_anchor_bound_to_one_alternative.eml - A whitelist accepts a value only if it is exactly "cat" or "dog", and it uses the regex engine correctly on every value. What the anchors bind to is computed below.
ok: true — round-trip fixpoint reached (python1 == python2)updated 2026-09-15
EML
eml# Self-authored for the EML case corpus (no external origin). A whitelist accepts
# a value only if it is exactly "cat" or "dog", and it uses the regex engine
# correctly on every value. What the anchors bind to is computed below.
#
# The check is careful. It applies the pattern to the real value, not a substring;
# it uses the engine's own regex; it runs on every value; and the intent is
# exactly 'the whole value is one of the two allowed words'.
#
# The pattern is ^cat|dog$, and alternation has the lowest precedence, so it reads
# as (^cat) or (dog$) - each anchor binds to one branch, not to both words.
100000 => values_tested
40000 => exactly_cat_or_dog
500 => starts_with_cat_or_ends_with_dog_not_exact
exactly_cat_or_dog + starts_with_cat_or_ends_with_dog_not_exact => accepted_by_ungrouped
exactly_cat_or_dog => accepted_by_grouped
accepted_by_ungrouped - accepted_by_grouped => wrongly_accepted
int(wrongly_accepted * 10000 / accepted_by_ungrouped) => wrongly_accepted_share_per_myriad
"values tested : " + str(values_tested) ^0
" exactly cat or dog : " + str(exactly_cat_or_dog) ^0
" start-cat or end-dog, not exact : " + str(starts_with_cat_or_ends_with_dog_not_exact) ^0
"" ^0
"accepted by ^cat|dog$ : " + str(accepted_by_ungrouped) ^0
"accepted by ^(cat|dog)$ : " + str(accepted_by_grouped) ^0
"wrongly accepted : " + str(wrongly_accepted) ^0
"share of accepted that is neither word : " + str(wrongly_accepted_share_per_myriad) + " per ten thousand" ^0
"" ^0
# ---- what the check verified ----
"the whitelist" ^0
" applies to : the real value, not a substring" ^0
" uses : the engine's own regex" ^0
" runs on : every value" ^0
" intent : the whole value is exactly cat or dog" ^0
" values skipped : 0" ^0
" verdict : EVERY ACCEPTED VALUE MATCHES THE PATTERN" ^0
"" ^0
" using the engine's regex over every value is the part" ^0
" done right here, and it is why a real cat or dog is" ^0
" always accepted" ^0
"" ^0
# ---- what the anchors bind to ----
"^cat|dog
EML
Starting…
quot; ^0
" precedence of alternation : the lowest of all" ^0
" so the pattern groups as : (^cat) or (dog$)" ^0
" what the left branch requires : starts with cat, end free" ^0
" what the right branch requires : ends with dog, start free" ^0
" so catfish and hotdog : both match, one per branch" ^0
"" ^0
# ---- what the caller got ----
"the result of the whitelist" ^0
" values it should accept : the " + str(exactly_cat_or_dog) + " exact words" ^0
" values it accepted : " + str(accepted_by_ungrouped) + ", prefixes and suffixes too" ^0
" neither-word values wrongly accepted : " + str(wrongly_accepted) ^0
" is the pattern malformed : no; it compiles and runs" ^0
" did the anchors cover both words : no; each bound to one" ^0
" branch, and the fixtures only used the exact words" ^0
"" ^0
# ---- null control ----
# The same alternation, grouped so the anchors apply to the whole choice:
# ^(cat|dog)$ instead of ^cat|dog$.
500 => nc_neither_word_accepted_ungrouped
0 => nc_neither_word_accepted_grouped
500 => nc_values_the_grouping_rejects
"null control - group the alternation, ^(cat|dog)
EML
Starting…
quot; ^0
" neither-word accepted, ungrouped : " + str(nc_neither_word_accepted_ungrouped) ^0
" neither-word accepted, grouped : " + str(nc_neither_word_accepted_grouped) ^0
" values the grouping now rejects : " + str(nc_values_the_grouping_rejects) ^0
" no value and no alternative changed; the anchors stopped" ^0
" binding to one branch and started binding to the choice" ^0
"" ^0
# ---- the rule ----
"what a ^cat|dog$ whitelist guarantees" ^0
" the value matches one of the branches : exactly, the" ^0
" engine's own match over every value" ^0
" the value is exactly cat or dog : not addressed;" ^0
" alternation binds looser than the anchors, so the" ^0
" pattern is (^cat) or (dog$) and accepts catfish and" ^0
" hotdog - " + str(wrongly_accepted) + " values that are neither word" ^0
"" ^0
"an anchor attaches to the branch beside it, not to the alternation as a whole;" ^0
"without a group the choice reaches past the anchors, and a whitelist meant to" ^0
"name two exact words instead names two open-ended halves" ^0
"" ^0
"It runs the engine's regex over every value - a real cat or dog always matches." ^0
"But ^cat|dog$ parses as (^cat) or (dog$), so catfish and hotdog pass; " + str(wrongly_accepted) ^0
"neither-word values were accepted, " + str(wrongly_accepted_share_per_myriad) + " per ten thousand of the accepted set," ^0
"until the alternation was grouped." ^0Python (deterministic transpilation)
pythonvalues_tested = 100000
exactly_cat_or_dog = 40000
starts_with_cat_or_ends_with_dog_not_exact = 500
accepted_by_ungrouped = exactly_cat_or_dog + starts_with_cat_or_ends_with_dog_not_exact
accepted_by_grouped = exactly_cat_or_dog
wrongly_accepted = accepted_by_ungrouped - accepted_by_grouped
wrongly_accepted_share_per_myriad = int(wrongly_accepted * 10000 / accepted_by_ungrouped)
print("values tested : " + str(values_tested))
print(" exactly cat or dog : " + str(exactly_cat_or_dog))
print(" start-cat or end-dog, not exact : " + str(starts_with_cat_or_ends_with_dog_not_exact))
print("")
print("accepted by ^cat|dog$ : " + str(accepted_by_ungrouped))
print("accepted by ^(cat|dog)$ : " + str(accepted_by_grouped))
print("wrongly accepted : " + str(wrongly_accepted))
print("share of accepted that is neither word : " + str(wrongly_accepted_share_per_myriad) + " per ten thousand")
print("")
print("the whitelist")
print(" applies to : the real value, not a substring")
print(" uses : the engine's own regex")
print(" runs on : every value")
print(" intent : the whole value is exactly cat or dog")
print(" values skipped : 0")
print(" verdict : EVERY ACCEPTED VALUE MATCHES THE PATTERN")
print("")
print(" using the engine's regex over every value is the part")
print(" done right here, and it is why a real cat or dog is")
print(" always accepted")
print("")
print("^cat|dog
EML
Starting…
quot;)
print(" precedence of alternation : the lowest of all")
print(" so the pattern groups as : (^cat) or (dog$)")
print(" what the left branch requires : starts with cat, end free")
print(" what the right branch requires : ends with dog, start free")
print(" so catfish and hotdog : both match, one per branch")
print("")
print("the result of the whitelist")
print(" values it should accept : the " + str(exactly_cat_or_dog) + " exact words")
print(" values it accepted : " + str(accepted_by_ungrouped) + ", prefixes and suffixes too")
print(" neither-word values wrongly accepted : " + str(wrongly_accepted))
print(" is the pattern malformed : no; it compiles and runs")
print(" did the anchors cover both words : no; each bound to one")
print(" branch, and the fixtures only used the exact words")
print("")
nc_neither_word_accepted_ungrouped = 500
nc_neither_word_accepted_grouped = 0
nc_values_the_grouping_rejects = 500
print("null control - group the alternation, ^(cat|dog)
EML
Starting…
quot;)
print(" neither-word accepted, ungrouped : " + str(nc_neither_word_accepted_ungrouped))
print(" neither-word accepted, grouped : " + str(nc_neither_word_accepted_grouped))
print(" values the grouping now rejects : " + str(nc_values_the_grouping_rejects))
print(" no value and no alternative changed; the anchors stopped")
print(" binding to one branch and started binding to the choice")
print("")
print("what a ^cat|dog$ whitelist guarantees")
print(" the value matches one of the branches : exactly, the")
print(" engine's own match over every value")
print(" the value is exactly cat or dog : not addressed;")
print(" alternation binds looser than the anchors, so the")
print(" pattern is (^cat) or (dog$) and accepts catfish and")
print(" hotdog - " + str(wrongly_accepted) + " values that are neither word")
print("")
print("an anchor attaches to the branch beside it, not to the alternation as a whole;")
print("without a group the choice reaches past the anchors, and a whitelist meant to")
print("name two exact words instead names two open-ended halves")
print("")
print("It runs the engine's regex over every value - a real cat or dog always matches.")
print("But ^cat|dog$ parses as (^cat) or (dog$), so catfish and hotdog pass; " + str(wrongly_accepted))
print("neither-word values were accepted, " + str(wrongly_accepted_share_per_myriad) + " per ten thousand of the accepted set,")
print("until the alternation was grouped.")stdout (executed)
textvalues tested : 100000
exactly cat or dog : 40000
start-cat or end-dog, not exact : 500
accepted by ^cat|dog$ : 40500
accepted by ^(cat|dog)$ : 40000
wrongly accepted : 500
share of accepted that is neither word : 123 per ten thousand
the whitelist
applies to : the real value, not a substring
uses : the engine's own regex
runs on : every value
intent : the whole value is exactly cat or dog
values skipped : 0
verdict : EVERY ACCEPTED VALUE MATCHES THE PATTERN
using the engine's regex over every value is the part
done right here, and it is why a real cat or dog is
always accepted
^cat|dog$
precedence of alternation : the lowest of all
so the pattern groups as : (^cat) or (dog$)
what the left branch requires : starts with cat, end free
what the right branch requires : ends with dog, start free
so catfish and hotdog : both match, one per branch
the result of the whitelist
values it should accept : the 40000 exact words
values it accepted : 40500, prefixes and suffixes too
neither-word values wrongly accepted : 500
is the pattern malformed : no; it compiles and runs
did the anchors cover both words : no; each bound to one
branch, and the fixtures only used the exact words
null control - group the alternation, ^(cat|dog)$
neither-word accepted, ungrouped : 500
neither-word accepted, grouped : 0
values the grouping now rejects : 500
no value and no alternative changed; the anchors stopped
binding to one branch and started binding to the choice
what a ^cat|dog$ whitelist guarantees
the value matches one of the branches : exactly, the
engine's own match over every value
the value is exactly cat or dog : not addressed;
alternation binds looser than the anchors, so the
pattern is (^cat) or (dog$) and accepts catfish and
hotdog - 500 values that are neither word
an anchor attaches to the branch beside it, not to the alternation as a whole;
without a group the choice reaches past the anchors, and a whitelist meant to
name two exact words instead names two open-ended halves
It runs the engine's regex over every value - a real cat or dog always matches.
But ^cat|dog$ parses as (^cat) or (dog$), so catfish and hotdog pass; 500
neither-word values were accepted, 123 per ten thousand of the accepted set,
until the alternation was grouped.Trace event types
eml:run:starteml:assigneml:outputeml:run:done