Proof target: ellipsis dot-run normalization
Relevant code: src/ellipsis.rs (replace_dot_runs), ADR 0005.
For a maximal unprotected dot run of length n, the implementation emits "…" * (n / 3) followed by "." * (n % 3). Since 0 <= n % 3 < 3, no replaceable triple remains in that run.
Goals
- Local correctness.
replace_dot_runs(s) maps each maximal run of n dots to ⌊n/3⌋ ellipses and n mod 3 dots, and preserves every non-dot character in order.
- Local idempotence.
replace_dot_runs(replace_dot_runs(s)) == replace_dot_runs(s).
- Protection stability (the important part). A region protected on the first run (URL, path, code span, code block, per ADR 0005) is still protected on the second run. Proving the arithmetic does not establish this; it requires that the emitted ellipsis characters cannot create or destroy a protection boundary.
Implementation recipe
- Verify
replace_dot_runs over Seq<char> with a spec fn normalize_runs, proving by induction on the run structure. This is a self-contained beginner-level Verus target and a good first kernel for the harness.
- Specify the protection predicate
spec fn protected(s, i) -> bool for the region scanner in src/ellipsis/; treat the URL/path regexes as external contracts in the ledger.
- Prove
lemma_ellipsis_char_is_neutral: inserting … at an unprotected position does not change protected at any other position. This is the lemma that makes the whole-feature idempotence follow.
- Ledger: local correctness and local idempotence; protection stability is a cross-pass result and depends on the fence kernel for code blocks.
Non-vacuity tests
- Witness proofs:
"a....b" yields "a….b"; "......" yields "……"; ".." unchanged.
- Mutation: emit
n % 3 + 1 trailing dots and confirm the idempotence lemma fails on the "......" witness (which would gain a triple).
- Executable: the existing
tests/data ellipsis fixtures plus the fence reproduction from the unmatched-block issue as a negative case (literal... inside a fence must be untouched).
Related issues
Proof target: ellipsis dot-run normalization
Relevant code:
src/ellipsis.rs(replace_dot_runs), ADR 0005.For a maximal unprotected dot run of length
n, the implementation emits"…" * (n / 3)followed by"." * (n % 3). Since0 <= n % 3 < 3, no replaceable triple remains in that run.Goals
replace_dot_runs(s)maps each maximal run ofndots to⌊n/3⌋ellipses andn mod 3dots, and preserves every non-dot character in order.replace_dot_runs(replace_dot_runs(s)) == replace_dot_runs(s).Implementation recipe
replace_dot_runsoverSeq<char>with aspec fn normalize_runs, proving by induction on the run structure. This is a self-contained beginner-level Verus target and a good first kernel for the harness.spec fn protected(s, i) -> boolfor the region scanner insrc/ellipsis/; treat the URL/path regexes as external contracts in the ledger.lemma_ellipsis_char_is_neutral: inserting…at an unprotected position does not changeprotectedat any other position. This is the lemma that makes the whole-feature idempotence follow.Non-vacuity tests
"a....b"yields"a….b";"......"yields"……";".."unchanged.n % 3 + 1trailing dots and confirm the idempotence lemma fails on the"......"witness (which would gain a triple).tests/dataellipsis fixtures plus the fence reproduction from the unmatched-block issue as a negative case (literal...inside a fence must be untouched).Related issues