assert(is_sorted(xs))) is proved by name, carried to callers, checked once (ADR-381)Open and answer this issue on GitHub.
ready · opened 2026-10-24 · updated 2026-11-03 · 1 comment
Owner, 2026-10-24, in the round on claim (b) of #796: he expected Nikaia to let a program say this list is sorted or this tree has only valid nodes, with the fact entering the ledger and paying off (no re-check, binary search, no re-sort). Checked on target/fast/nikaia (0.0.1204), probes in docs/facts-about-data.md:
assert(is_sorted(v)) with a pure bool function is allowed but refused (NK1300, not a comparison of whole numbers the prover reads). It is not made a precondition, so no caller is asked and nothing after it knows it. At unproved-claims = "warn" (project build) it is walked at run time and stops the program on [3, 1, 2].Tree { nodes, root, assert(0 <= root && root < nodes.len()) } proves t.nodes[t.root]. A child index read from a node (t.nodes[l]) stays checked: no fact about what the elements hold.0 <= lo <= hi <= len, not sortedness.Decision: ADR-381, Part III 14.2 (What the prover reads). A pure bool call over unchanged values is a name of the prover; it is a fact after its assert, from a precondition, a postcondition or a type rule; it is carried to callers and published in the ledger; not proved it is refused or (at warn) checked once, at the call. Its body is not read: it removes only its own check. Reading the body (every element, neighbours in order) is the owner’s question in #798.
nikaia run --unproved-claims warn FILE.nika still refuses with NK1300; the same with [build] unproved-claims = "warn" in a project builds and checks. The flag must win (--help says it overrides the manifest).
b. A struct rule at a literal whose list is written inline, Tree { nodes: [Node { left: 0, value: 7 }], root: 0 } with assert(root < nodes.len()), is refused: tree is not a whole number the prover reads; with let ns = [...] first it is proved. The literal’s length must be known as for a let.crates/nikaia-std/src/tools/prove_terms.nika claim_term, the name keying used for xs.len()): a call meeting ADR-381 D1 becomes an integer name prop@... keyed by the function and its argument names, read as == 1, with 0 <= name <= 1; invalidated where an argument may change. Tests: assert(p(v)); assert(p(v)) second proved; assert(p(v)); v.push(1); assert(p(v)) second not proved; assert(p(v) && v.len() > 0) proves v[0]’s other claims unchanged.nikaia.contracts as written; a postcondition assert(p(result)) known of let c = f(..); a struct rule assert(p(items)) known of every value seen. A call that knows the property owes nothing. Tests: chain a -> b -> c each requiring is_sorted(v): one check, at a’s caller, at warn; at error a caller with no fact is NK1300 naming the property.--asserts: proved: known from the assert, precondition, postcondition or rule. Test in crates/nikaia/tests/it/prove.rs.Not in this issue: unfolding a property’s body, Vec::is_sorted/binary_search in std, using a fact to choose an algorithm (#798).
Still true on the current develop, found while writing the prover chapter of the guide: assert(is_sorted(xs)) gives NK1300, and nikaia run --unproved-claims=warn FILE still refuses it (step 0a). Part III 14.2 describes ADR-381 properties in the present tense, as though they were built. The guide says they are planned. The specification’s wording must be fixed with this issue’s build, or marked as not yet built in the meantime.
Generated by Claude Code