[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill-aptos-move-inf":3,"mdc-fv8ej2-key":29,"related-repo-aptos-move-inf":4241,"related-org-aptos-move-inf":4309},{"slug":4,"name":4,"fn":5,"description":6,"org":7,"tags":12,"stars":20,"repoUrl":21,"updatedAt":22,"license":23,"forks":20,"topics":24,"repo":25,"sourceUrl":27,"mdContent":28},"move-inf","infer specifications for Move packages","Infer specifications for a Move package",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},"aptos","Aptos Labs","https:\u002F\u002Fpexgzepcugksgbtrxkhf.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Forg-logos\u002Faptos.png","aptos-labs",[13,17],{"name":14,"slug":15,"type":16},"Web3","web3","tag",{"name":18,"slug":19,"type":16},"Data Modeling","data-modeling",0,"https:\u002F\u002Fgithub.com\u002Faptos-labs\u002Faptos-ai","2026-07-19T06:03:10.203983",null,[],{"repoUrl":21,"stars":20,"forks":20,"topics":26,"description":23},[],"https:\u002F\u002Fgithub.com\u002Faptos-labs\u002Faptos-ai\u002Ftree\u002FHEAD\u002Fplugins\u002Fmove-flow\u002Fskills\u002Fmove-inf","---\nname: move-inf\ndescription: Infer specifications for a Move package\n---\n\nBefore doing any work, use TaskCreate to create one task for each\n`**Task:**` entry listed below. Then execute them in order, marking\neach in_progress when you start it and completed when you finish.\n\n\n\n\n## Inference Tasks — Execute In Order\n\n**Skip test functions.** Do not infer specs for `#[test]` or `#[test_only]`\nfunctions — the WP tool also skips them automatically.\n\n**Task: Synthesize loop invariants.** For every loop lacking an invariant in a\nfunction matching the `filter`, add one marked as `[inferred]`. Define\nrecursive spec helper functions as needed. Avoid the Common Pitfalls\ndescribed in the reference material below.\nWhen using `spec_output: \"file\"`, add loop invariants directly in the source\n(they must stay inside the function body), but place any new spec helper\nfunctions and lemmas in the `.spec.move` file inside a `spec module { }` block.\n\n**Task: Infer weakest preconditions.** With invariants in place, run the WP tool with the `filter`.\nLet the WP tool generate the specs — do not write them by hand.\n\n**Task: Simplify inferred specs.** Apply the simplification rules from the\nreference material below. Every function must keep both `ensures` and\n`aborts_if` conditions — do not drop `aborts_if` just because it is hard\nto verify.\nWhen using `spec_output: \"file\"`, all inferred spec helper functions and\nlemmas belong in the `.spec.move` file inside a `spec module { }` block,\nand function conditions go in `spec fun_name { }` blocks in the same file.\n\n\n\n\n## Verification Tasks — Execute In Order\n\n**Task: Full-scope verification run.** Run verification for the full requested scope\nwith `timeout` set to 5. This gives an\noverview of all failures — both logical errors and timeouts.\n\n**Task: Fix logical errors.** If there are any logical errors, iterate to fix them\nusing the `exclude` parameter of the verify tool to exclude functions whose\nverification timed out. Only continue once all non-timeouts cleanly pass.\n\n**Task: Resolve timeouts.** Resolve timeouts one by one calling the prover with a\nfunction-level filter and `timeout` set to 10.\nApply the timeout resolution strategies from the reference material below\n(spec helpers, lemmas, proofs). If a function cannot be resolved after\n2 attempts and the user did not request\notherwise, add `pragma verify_duration_estimate = N;` where `N` is the exact\ntimeout at which you observed verification succeed. If verification never\nsucceeded, use `pragma verify = false;` instead.\n\n**Task: Final full-scope verification.** Run the prover for the full requested scope\nusing `timeout` 10 to verify success. Functions\nwith `pragma verify_duration_estimate = N;` where `N` exceeds the timeout will\nbe automatically skipped — this is expected.\n\n\n\n\n\n\n\nThe reference material below supports the tasks above.\n\n\n\n\n\n## Move Specification Language\n\nMove specifications use `spec` blocks to express formal properties that are checked\nby the Move Prover.\n\n### Function spec clauses\n\nThese appear in `spec fun_name { ... }` blocks. Spec blocks always appear after the function\ndefinition. If `fun_name` clashes with a soft keyword (e.g. `lemma`), use `spec @fun_name { ... }`\nto escape it.\n\n- `ensures \u003Cexpr>`: Postcondition that must hold when the function returns normally.\n  Evaluated in the **post-state**. Use `old(expr)` to refer to pre-state values.\n- `aborts_if \u003Cexpr>`: Condition under which the function may abort. **Evaluated in the\n  pre-state** — do not use `old()` (see `old()` usage rules below). If any\n  `aborts_if` conditions are present, the function must abort if and only if one of the\n  conditions holds. Omitting all `aborts_if` clauses means abort behavior is *unspecified*\n  (any abort is allowed). To express that a function never aborts, write `aborts_if false;`.\n- `requires \u003Cexpr>`: Precondition that callers must satisfy. **Evaluated in the pre-state** —\n  Do not use `old()` (see `old()` usage rules below).\n- `modifies \u003Cresource>`: Declares which global resources the function may modify.\n\n### Loop invariants\n\nLoop invariants appear in a `spec` block after the loop body:\n\n```move\nwhile (cond) {\n    \u002F\u002F body\n} spec {\n    invariant \u003Cexpr>;\n};\n```\n\n- `invariant \u003Cexpr>`: A property that holds before the first iteration and is preserved by\n  each iteration. `old(x)` is only allowed on function parameters (see `old()` usage rules below.)\n\nLoops without invariants cause the prover to *havoc* all loop-modified variables, which can\nproduce vacuous, incorrect, or overly weak specifications. Every loop needs an invariant —\nexamine the actual `while` loops in function bodies to find all loops that lack one.\n\nA good invariant:\n1. Holds before the first iteration (initial values satisfy it).\n2. Is preserved by each iteration (inductive step).\n3. Relates loop-modified variables to function parameters and constants\n   (e.g., bounds like `i \u003C= n`, accumulators like `sum == i * step`).\n\n### Expressions in specs\n\n- `old(expr)`: Value of `expr` at function entry. See `old()` usage rules below for\n  where this is allowed.\n- `result`: Return value. Only valid in `ensures`.\n- `global\u003CT>(addr)`: Global resource of type `T` at address `addr`.\n- `exists\u003CT>(addr)`: True if a resource of type `T` exists at address `addr`.\n- Numeric type bounds: `MAX_U8`, `MAX_U16`, `MAX_U32`, `MAX_U64`, `MAX_U128`, `MAX_U256`.\n- **No dereference or borrow**: `*e` and `&e` are not allowed in spec\n  expressions. Spec expressions operate on values, not references — access\n  fields directly (e.g. `v.field`, not `(*v).field` or `(&v).field`).\n\n### `old()` usage rules\n\n`old(expr)` means \"value of `expr` at function entry.\" It is only valid in specific contexts:\n\n**Wrong \u002F Right examples:**\n\n```move\n\u002F\u002F WRONG: old() in aborts_if — compilation error\naborts_if old(x) + old(y) > MAX_U64;\n\u002F\u002F RIGHT: aborts_if is pre-state, just use the variables directly\naborts_if x + y > MAX_U64;\n\n\u002F\u002F WRONG: old() in requires — compilation error\nrequires old(len(v)) > 0;\n\u002F\u002F RIGHT: requires is pre-state\nrequires len(v) > 0;\n\n\u002F\u002F WRONG: old(local) in loop invariant — compilation error\ninvariant old(sum) \u003C= old(n) * MAX_U64;\n\u002F\u002F RIGHT: sum is a local — use it directly; n is a parameter — old(n) is ok\ninvariant sum \u003C= old(n) * MAX_U64;\n\n\u002F\u002F WRONG: old(resource) in loop invariant — compilation error\ninvariant old(global\u003CT>(addr)).field == 0;\n\u002F\u002F RIGHT: use resource directly\ninvariant global\u003CT>(addr).field == 0;\n```\n\n### Referring to Behavior of other Functions\n\nWhen specifying a function that calls other functions **which are not inline functions**, you\ncan use **behavioral predicates** to abstract the callee's specification without inlining its\ndetails. These built-in predicates lift a function's spec clauses into expressions:\n\n- `requires_of\u003Cf>(args)` — true when `f`'s `requires` clauses hold for `args`.\n- `aborts_of\u003Cf>(args)` — true when `f`'s `aborts_if` clauses hold for `args`.\n- `ensures_of\u003Cf>(args, result)` — true when `f`'s `ensures` clauses hold for\n  `args` and the given `result` value(s). For functions returning unit, omit\n  the result argument. For multiple return values, pass `result_1, result_2, ...`.\n- `result_of\u003Cf>(args)` — the return value of `f` when called with `args`,\n  usable in `let` bindings and expressions inside spec blocks.\n\nThe `\u003Cf>` target can be:\n- A **function parameter** of function type: `ensures_of\u003Cf>(x, result)` where\n  `f` is a parameter with type `|u64| u64`.\n- A **named function** (same module or cross-module): `ensures_of\u003Cincrement>(x, result)`\n  or `ensures_of\u003CM::increment>(x, result)`.\n- A **generic function** with explicit or inferred type arguments:\n  `ensures_of\u003Cidentity\u003Cu64>>(x, result)` or `ensures_of\u003Cidentity>(x, result)`.\n\n**Examples:**\n\nSpecifying a higher-order function that applies a callback:\n\n```move\nfun apply(f: |u64| u64, x: u64): u64 { f(x) }\nspec apply {\n    aborts_if aborts_of\u003Cf>(x);\n    ensures ensures_of\u003Cf>(x, result);\n}\n```\n\nUsing `result_of` to chain calls in a spec (e.g. `f(f(x))`):\n\n```move\nfun apply_seq(f: |u64| u64 has copy, x: u64): u64 { f(f(x)) }\nspec apply_seq {\n    let y = result_of\u003Cf>(x);\n    requires requires_of\u003Cf>(x) && requires_of\u003Cf>(y);\n    aborts_if aborts_of\u003Cf>(x) || aborts_of\u003Cf>(y);\n    ensures result == result_of\u003Cf>(y);\n}\n```\n\nReferring to a named function's behavior from a caller:\n\n```move\nspec bar {\n    ensures ensures_of\u003Cincrement>(x, result);\n}\n```\n\nUsing `result_of` inside loop invariants with closures:\n\n```move\nspec {\n    invariant forall j in 0..i: !result_of\u003Cpred>(v[j]);\n};\n```\n\n### Property markers\n\nThe `[inferred]` property marks conditions that were not written by the user. Its value indicates\nthe origin or quality:\n\n- `[inferred]`: Automatically inferred by weakest-precondition (WP) analysis. It may be overly complex, redundant,\n  or occasionally incorrect.\n- `[inferred = vacuous]`: Inferred by WP but detected as potentially vacuous (trivially true)\n  due to unconstrained quantifier variables. Typically results from missing loop invariants.\n- `[inferred = sathard]`: Inferred by WP but contains quantifier patterns that are hard for\n  SMT solvers. Likely to cause verification timeouts — should be simplified or reformulated.\n\n\n### Links\n\n- [Move Specification Language](https:\u002F\u002Faptos.dev\u002Fen\u002Fbuild\u002Fsmart-contracts\u002Fprover\u002Fspec-lang)\n\n\n\n## Checking Move Code\n\nUse the `move_package_status` MCP tool to check for compilation errors and warnings.\n\n- Call `move_package_status` with `package_path` set to the package directory.\n- The tool sets error and returns detailed error messages if the package does not compile.\n\nNotice that like with a build system, the tool is idempotent, and does not cause recompilation\nif the compilation result and sources are up-to-date.\n\n\n## Package Manifest\n\nUse the `move_package_manifest` MCP tool to discover source files and dependencies\nof a Move package:\n\n- Call `move_package_manifest` with `package_path` set to the package directory.\n- The result includes `source_paths` (target modules) and `dep_paths` (dependencies).\n\n\n## Querying Package Structure\n\nUse the `move_package_query` MCP tool to inspect the structure of a Move package.\n\nParameters:\n\n- **`package_path`** (required) — path to the Move package directory.\n- **`query`** (required) — one of the query types below.\n- **`function`** (required for `function_usage`) — function name in the form `module_name::function_name`.\n\n### Query Types\n\n- **`dep_graph`** — returns a map from each module to the modules it depends on.\n  Useful for understanding module layering and import structure.\n- **`module_summary`** — returns a summary of each module's constants, structs,\n  and functions. Useful for getting an overview without reading all source files.\n- **`call_graph`** — returns a function-level call graph as a map from each\n  function to the functions it calls.\n- **`function_usage`** — returns direct and transitive calls\u002Fuses for a given\n  function. \"called\" = direct calls; \"used\" = direct calls + closure captures.\n  Requires the `function` parameter.\n\n\n\n## Spec Inference Reference\n\n\n\n\n### WP Tool\n\nUse `move_package_wp`, a weakest precondition (WP)\ninference tool for deriving specs. Do not run this tool outside of this workflow.\n\nParameters:\n\n- **`package_path`** (required) — path to the Move package directory.\n- **`filter`** (optional) — `module_name` or `module_name::function_name`.\n  When omitted, all target modules are inferred.\n- **`spec_output`** (optional, default `\"inline\"`) — where to write inferred specs.\n  `\"inline\"` injects specs into the original source files.\n  `\"file\"` writes separate `.spec.move` files alongside the sources, leaving\n  originals untouched.\n\n**Important:** If the user asks for specs in a separate file, in a spec file, or\nto keep the source untouched, you **must** pass `spec_output: \"file\"`. Only use\nthe default `\"inline\"` when the user wants specs added directly into their source.\n\nIf the program contains loops, they are broken into exit and iteration points.\nLoop variables are havoced and the loop invariant is expected to fix them.\nWithout loop invariants, derived WPs leave values in arbitrary state, resulting\nin `[inferred = vacuous]` properties. You must add loop invariants to fix this.\n\n**Before every WP re-run:** remove all existing `[inferred]`,\n`[inferred = vacuous]`, and `[inferred = sathard]`\nconditions from spec blocks in scope. The WP tool will regenerate them; keeping\nstale copies leads to duplicate conditions.\n\n\n\n\n\n\n### Common Pitfalls in AI Generated Spec Expressions\n\nRespect the `old()` usage rules and expression restrictions from the spec\nlanguage reference above — violating them causes compilation errors. Additionally:\n\n- **Do not forget space after property.** Write `aborts_if [inferred] !exists p` \n  with spaces separating the `[..]` property.\n\n### Avoiding Duplicate Conditions\n\nBefore adding any condition (ensures, aborts_if, loop invariant, etc.), check\nwhether an equivalent condition already exists in the same spec block. Do not\nadd a condition that is semantically identical to one already present — even if\nthe WP tool produced it again.\n\n### Respecting Filter Scope\n\nWhen a `filter` restricts inference to a specific function or module, only modify\nspec blocks for functions within that scope. Do not touch, add, or alter specs\nof any function outside the filter. Leave all other code and spec blocks exactly\nas they are.\n\n### Marking Inferred Conditions\n\nEvery condition you write during inference — whether during loop invariant\nsynthesis or simplification — must carry the `[inferred]` property.\nConditions without\n`[inferred]` are treated as user-written and will not be cleaned up on re-runs.\n\n```\nensures [inferred] result == x + 1;\naborts_if [inferred] x + y > MAX_U64;\ninvariant [inferred] acc == sum_up_to(i);\n```\n\nNever write a bare `ensures`, `aborts_if`, or `invariant` during inference.\n\n### Synthesizing Loop Invariants\n\nAdd loop invariants for every loop in the target code which doesn't yet have one.\nRemove all existing `[inferred]` and `[inferred = *]`\nconditions.\n\n**`old()` in loop invariants:** `old(x)` is only allowed when `x` is a simple\nfunction parameter name. To refer to a value from before the loop, save it into\na `let` binding before the loop and reference that local in the invariant.\n\nLoop invariants often need **recursive spec helper functions** to express\nproperties about values built up across iterations (e.g. partial sums,\naccumulated vectors, running products). When no existing spec function captures\nthe relationship, define a new `spec fun` in the same module. Typical pattern:\n\n```\nspec fun sum_up_to(n: u64): u64 {\n    if (n == 0) { 0 } else { n + sum_up_to(n - 1) }\n}\n```\n\nThen reference the helper in the loop invariant:\n\n```\ninvariant [inferred] acc == sum_up_to(i);\n```\n\nCreate as many helpers as needed to make invariants precise and verifiable.\nAdd a `\u002F\u002F\u002F` doc comment to every new spec helper explaining the property it\ncaptures. Place new spec helper functions below the Move function and spec\nblock that introduce them. Place lemmas for a helper directly beneath that\nhelper's declaration.\n\n### Data Invariants and Global Update Invariants\n\nData invariants (`spec Struct { invariant \u003Cexpr>; }`) express properties that\nmust hold for every instance of a struct at all times. The prover checks them on\nconstruction and after every mutation.\n\nGood candidates for data invariants:\n- Positivity \u002F non-zero bounds on fields that are denominators or reserves\n  (e.g., `invariant balance > 0;`). These eliminate impossible states and help the\n  prover rule out division-by-zero or underflow in callers.\n- Relationships between fields that hold by construction and are preserved by\n  all operations (e.g., `invariant len == vector::length(data);`).\n\nDo NOT add data invariants that are broken by normal operations. For example,\nan AMM pool's exchange rate changes after every swap — a fixed-ratio invariant\nlike `invariant x == y;` will fail verification on swap.\n\nGlobal update invariants (`spec module { invariant update ...; }`) constrain\nhow a resource changes between its old and new state during any modification.\nThey are verified once per function that modifies the resource, then assumed at\nevery call site — including inside loops. This makes them powerful for loop\nverification: the prover gets the property at each iteration for free without\nneeding recursive spec helpers.\n\n```\nspec module {\n    invariant update forall addr: address\n        where old(exists\u003CT>(addr)) && exists\u003CT>(addr):\n        old(global\u003CT>(addr)).field \u003C= global\u003CT>(addr).field;\n}\n```\n\nGood candidates for update invariants:\n- Monotonicity properties: a value that only grows or only shrinks\n  (e.g., total supply, sequence numbers, timestamps).\n- Conservation laws: a quantity preserved across state transitions\n  (e.g., `old(x) + old(y) == x + y` for token transfers).\n- Product bounds: for AMM-style contracts, the constant-product property\n  `old(rx) * old(ry) \u003C= rx * ry` (non-decreasing due to integer division\n  rounding). This is verified once on the swap function, then the prover uses\n  it at every loop iteration to bound intermediate reserve values without\n  recursive spec helpers.\n\nUpdate invariants are especially valuable when loop bodies call opaque functions.\nThe prover cannot inline the function body but CAN use the update invariant to\nconstrain how the resource changed — bridging the gap between opaque call\nsemantics and loop invariant preservation.\n\n**Combining data and update invariants with loops:** A data invariant like\n`x > 0 && y > 0` plus an update invariant like `old(x) * old(y) \u003C= x * y`\ngives the prover both a floor on individual fields and a relationship between\nthem at every loop step — without any recursive spec functions or manual\nunfolding. This pattern is the key to verifying iterative operations over\nstateful resources.\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n## Writing and Editing Specs\n\nWhen writing or editing specifications:\n\n1. Use `move_package_manifest` to discover source files.\n2. Read the function body to understand its behavior and abort conditions.\n3. Write `spec fun_name { ... }` blocks after each function, following the Move Specification\n   Language rules above.\n4. Write `spec lemma lemma_name ...` block after the function for which they are introduced.\n5. Spec functions are put into a `spec fun` declarations.\n6. If the project already uses `.spec.move` files, put new specs into that file instead of the \n   main Move file.\n\n**`.spec.move` files:** A `.spec.move` file is compiled as part of the same module\nas the corresponding source file. Use `spec module { }` (the keyword `module`,\nnot a module name) to declare module-level spec items (helper functions, lemmas).\nUse `spec fun_name { }` to add conditions to functions defined in the main source.\nThere is no `spec \u003Cmodule_name> { }` syntax — `spec name { }` always targets a\nfunction named `name`.\n\n### Simplifying Specifications\n\nWork through the following in order when cleaning up inferred or hand-written specs.\n\n**Remove vacuous conditions.** Delete every condition marked `[inferred = vacuous]`.\nThese arise from havoced loop variables without sufficient invariants and are\nsemantically meaningless (e.g.\n`ensures [inferred = vacuous] forall x: u64: result == x`).\n\n**Eliminate quantifiers.** Conditions with quantifiers over unbounded types\n(`forall x: u64`, `exists x: u64`, `forall x: address`) cause SMT solver timeouts.\nThey are often marked `[inferred = sathard]` but not always. Replace each with an\nequivalent **non-quantified** expression:\n\n- `exists x: u64: x \u003C n && f(x)` — replace with a concrete bound or closed-form\n  expression derived from the loop logic.\n- `forall x: address: x != a ==> g(x)` — this expresses a frame condition (\"nothing\n  else changed\"). Replace with an explicit `modifies` clause or enumerate the affected\n  addresses.\n\n**Ensure quantifiers have triggers.** Quantifiers without triggers must be avoided. Move \nsupports lists of triggers as in `Q x: T, y: R {p1, .., pn}..{q1, .., qn}: e`, where each outer \nlist is an alternative where all inner patterns must match. Notice that only triggers over \nuninterpreted functions are allowed, not over builtin operators.\n\n**Simplify `update_field` expressions.** The WP engine uses\n`update_field(s, field, val)` for struct mutations. Rewrite to direct struct\nconstruction when all fields are determined, e.g.:\n\n- `update_field(old(global\u003CT>(addr)), value, v)` becomes\n  `T { value: v, ..old(global\u003CT>(addr)) }`, or when the struct has a single field,\n  simply `T { value: v }`.\n- Nested `update_field(update_field(old(p), x, a), y, b)` becomes\n  `Point { x: a, y: b }` when all fields are covered.\n\n**Consolidate unrolled specs.** When `pragma unroll` is used, the WP produces one\ncondition per unrolling step (e.g. `n == 0 ==> ...`, `n == 1 ==> ...`, ...,\n`k \u003C n ==> ...`). If there is a closed-form generalization, replace the case list\nwith a single condition. Remove the `pragma unroll` once the closed-form is in place.\n\n**General cleanup:**\n\n- Fix `old()` usage: `old()` in `aborts_if` or `requires` is invalid — those\n  clauses are already evaluated in the pre-state. Remove `old()` wrappers.\n- Remove redundant conditions implied by others or by language guarantees (e.g. an\n  `aborts_if` subsumed by a stronger one).\n- Simplify arithmetic. The WP engine mirrors the computation steps, producing\n  expressions that can be algebraically reduced:\n  - Combine terms: `(n - 1) * n \u002F 2 + n` simplifies to `n * (n + 1) \u002F 2`.\n  - Flatten nested offsets: `old(v) + 1 + 1` becomes `old(v) + 2`.\n  - Simplify overflow bounds: `v + (n - 1) > MAX_U64 - 1` becomes `v + n > MAX_U64`.\n  - Specs use mathematical (unbounded) integers, so unlike Move code there is no\n    risk of underflow in spec expressions — reorder freely for clarity.\n- **Keep `[inferred]` markers** on all inferred conditions — they distinguish\n  inferred specs from user-written ones and are needed for WP re-runs.\n  Remove `[inferred = vacuous]` and `[inferred = sathard]` conditions entirely\n  (as described above), but keep plain `[inferred]` on conditions you retain.\n- **Keep `pragma opaque = true;`** — never remove it. It is essential for\n  verification performance, not an inference artifact. If a function with\n  `pragma opaque` fails verification, add `pragma verify = false;` rather\n  than removing the opaque pragma.\n\n### Additional Rules for Editing Specs\n\n1. **Do not change function bodies.** Only modify `spec` blocks and their contents.\n2. **Preserve** any user-written (non-inferred) specifications exactly as they are.\n3. **Never drop `aborts_if` conditions.** Every function that can abort must have\n   `aborts_if` conditions. The WP tool infers both `ensures` and `aborts_if` —\n   simplify them but never remove them just because they are complex or hard to\n   verify. If an `aborts_if` needs rewriting, replace it with a semantically\n   equivalent expression, do not delete it.\n4. **Never remove `pragma opaque`.** The WP tool marks inferred specs as opaque\n   so the prover uses the spec contract instead of inlining the function body.\n   Removing it causes verification to re-analyze the implementation, leading to\n   timeouts. Preserve `pragma opaque = true;` in every spec block that has it.\n   If verification fails on an opaque function (e.g., the prover cannot reason\n   about closure side effects), add `pragma verify = false;` to disable\n   verification while keeping the spec contract intact for callers.\n5. **Never duplicate conditions.** Before adding any condition to a spec block,\n   check whether an equivalent condition already exists. Do not create a condition\n   that is semantically identical to one already present in the same spec block.\n6. **No empty spec blocks.** Never create or leave behind an empty\n   `spec fun_name {}` block. If removing inferred conditions would leave a spec\n   block with no conditions or pragmas, delete the entire block instead.\n\n\n\n\n\n## Proofs and Lemmas\n\n### Example\n\n```move\nspec fun sum(n: u64): u64 {\n    if (n == 0) { 0 } else { n + sum(n - 1) }\n}\n\nspec lemma monotonicity(x: num, y: num) {\n    requires x \u003C= y;\n    ensures sum(x) \u003C= sum(y);\n} proof {\n    if (x \u003C y) {\n        assert sum(y - 1) \u003C= sum(y);\n        apply monotonicity(x, y - 1);\n    }\n}\n\n\nfun sum_up_to(n: u64): u64 { \u002F* iterative impl *\u002F }\nspec sum_up_to {\n    requires n \u003C= 5;\n    ensures result == sum(n);\n} proof {\n   forall x,y {sum(x), sum(y)} apply monotonicity(x, y);\n}\n```\n\n### Proofs\n\nA proof consists of a sequence of\nproof statements together with if-then-else and let bindings.\n\nProof statements: `let name = Expr`, `if (Expr) Proof else Proof`,\n`assert Expr`, `assume Expr`, `apply LemmaInstance`,\n`forall QuantifierDecls [Patterns] apply LemmaInstance`,\n`calc (Expr { RelOp Expr })`.\n\nA proof block can be attached to any specification block as postfix to that block, for example:\n\n```\nspec sum_to_n {\n  ensures result == sum(n);\n} proof {\n  forall x: u64, y: u64 apply Monotonicity(x, y);\n}  \n```\n\nA proof is translated by mapping it to a sequence of assumes\u002Fasserts at the\nverification entry points of a function.\n\n- The split statement is translated by creating different verification variants for each value split \n  with according assumptions of the value at the split point and otherwise identical content.\n- The apply statement is translated by injecting pre\u002Fpost conditions of the (expected to be proven) lemma.\n  This is very similar like calling an opaque function in Move code.\n\n### Lemmas\n\nA Lemma is a member of a specification block, similar like a spec function. Its\nuser syntax is:\n\n```\nspec fun sum(n: u64): u64 {\n    if (n == 0) { 0 } else { n + sum(n - 1) }\n}\nspec lemma sum_monotonicity(x: num, y: num) {\n    requires x \u003C= y;\n    ensures sum(x) \u003C= sum(y);\n} proof {\n    if (x \u003C y) {\n        assert sum(y - 1) \u003C= sum(y);\n        apply sum_monotonicity(x, y - 1);\n    }\n}\n```\n\nOr inside a `spec module { }` block (the keyword `module`, not a module name):\n\n```\nspec module {\n  fun sum ...\n  lemma sum_monotonicity ...\n}\n```\n\n**Important:** `spec name { }` always targets a *function* named `name`.\nThere is no `spec \u003Cmodule_name> { }` syntax. Module-level items (helper\nfunctions, lemmas) go inside `spec module { }`. Lemmas are **not valid**\ninside function spec blocks (`spec fun_name { }`).\n\nThe `spec lemma` shortcut is sugar for `spec module { lemma ... }`, analogous\nto the `spec fun` shortcut for helper functions.\n\nIt has a parameter list like a spec function (but no return value) followed by a\nspecification block (with requires, ensures, and pragmas the only allowed conditions).\nAttached to this is an (optional) proof.\n\nLemma names are in a separate namespace. They are scoped to modules,\nsimilar like specification functions. They can only be referenced from\nproof 'apply' statements.\n\n\n\n\n## Verification \n\n### Verification Tool\n\nUse `move_package_verify` to run the Move Prover on a package and\nformally verify its specifications:\n\n- Call with `package_path` set to the package directory and `timeout` set to\n  5.\n- The tool returns \"verification succeeded\" when all specs hold, or a diagnostic with a\n  counterexample when a spec fails.\n\n#### Narrowing scope with filters\n\nUse the `filter` parameter to restrict the verification scope:\n\n- **Single function:** set `filter` to `module_name::function_name`.\n- **Single module:** set `filter` to `module_name`.\n\n#### Excluding targets\n\nUse the `exclude` parameter to skip specific functions or modules while\nverifying the rest of the scope:\n\n- **Exclude function(s):** set `exclude` to `[\"module_name::function_name\"]`.\n- **Exclude module(s):** set `exclude` to `[\"module_name\"]`.\n\nExclusions take precedence over the `filter` scope — a target that matches both\n`filter` and `exclude` is excluded. This is useful in the \"Fix logical errors\" task to skip timed-out\nfunctions without modifying source files.\n\n#### Setting timeout\n\nVerification can be long-running (10 seconds or more). Always explicitly specify a timeout. \nStart with a low timeout of 5 to get quick feedback.\nIncrease the timeout to not more than 10 in the case of \ninvestigating difficult verification problems. \n\n### Diagnosing Verification Failures\n\nWhen the prover reports a counterexample or error:\n\n- **Postcondition failure**: The `ensures` clause doesn't hold for some execution path.\n  Check whether an edge case is missing or the condition is too strong.\n- **Abort condition failure**: An abort path is not covered by `aborts_if`. Trace which\n  operations can abort (arithmetic overflow, missing resource, vector out-of-bounds) and\n  add the missing condition.\n- **Wrong `old()` usage**: Using `old()` in `aborts_if` or `requires` causes a compilation\n  error. Remove it — those clauses are already evaluated in the pre-state.\n- **Loop-related failures**: Missing or too-weak loop invariants cause havoced variables.\n  Strengthen the invariant to constrain all loop-modified variables.\n- **Timeout (\"out of resources\")**:\n\n  Do not delete, comment out, or weaken any `aborts_if` or `ensures`\n  condition to resolve a timeout. This includes adding\n  `pragma aborts_if_is_partial;`, which silently suppresses uncovered abort\n  paths. Every condition is assumed semantically correct; removing one hides\n  real properties and makes the specification unsound.\n\n  Timeout resolution strategies — try these in order, and iterate\n  aggressively before resorting to `pragma verify_duration_estimate`:\n\n  1. **Add data invariants and global update invariants** to constrain\n     resource state. These are checked once per modifying function and then\n     assumed at every call site (including inside loops), giving the prover\n     facts for free without recursive helpers. See the inference reference\n     for details on when to use each kind.\n\n  2. **Introduce spec helper functions** that capture intermediate properties.\n     Factor complex `ensures` into compositions of simpler helpers. Each\n     helper should express one logical step the solver can verify independently.\n\n  3. **Add lemmas** to establish properties about spec helpers\n     (e.g. monotonicity, induction steps) that the solver cannot discover\n     on its own. Lemmas are proven propositions — do not introduce axioms.\n\n  4. **Add `proof { ... }` blocks** to function specs or lemmas to guide\n     the verifier with `assert`, `apply`, and `calc` steps. Use `apply`\n     to instantiate lemmas at specific points in the proof.\n\n  5. **Rewrite spec expressions** while preserving their meaning — factor\n     out common sub-expressions into `let` bindings, reorder conjuncts,\n     or replace a complex closed-form with a recursive helper connected\n     by a lemma.\n\n  When you use universal lemma application, always add triggers, as\n  in `forall x: u64 {f(x)} apply lemma_for_f(x)`.\n\n  **Avoid non-linear arithmetic in spec helpers.** SMT solvers handle linear\n  arithmetic well but struggle with multiplication, division, or modulo between\n  two non-constant expressions. Prefer additive recurrences over closed-form\n  products. If a non-linear closed form is needed, connect it to a recursive\n  helper via a lemma so the solver reasons about each step linearly.\n\n  **Do not redefine built-in operations as spec helpers.** The SMT solver\n  already understands `*`, `\u002F`, `%`, comparisons, and bitwise operations\n  natively. Only introduce a spec helper when it encodes logic the solver\n  does not have built in — such as a loop accumulation pattern or a\n  recursive data-structure traversal.\n\n  **Document every function and lemma.** Add a `\u002F\u002F\u002F` doc comment explaining\n  what property it captures and why it is needed. Place new spec helper\n  functions below the Move function that introduces them. Place lemmas\n  directly beneath their helper's declaration.\n\n\n\n\n\n## Task\n\nRun specification inference workflow for current package.\n",{"data":30,"body":31},{"name":4,"description":6},{"type":32,"children":33},"root",[34,51,58,85,135,152,213,219,237,255,296,326,331,337,350,357,394,530,536,548,606,635,655,660,695,701,892,903,920,928,1100,1106,1125,1267,1280,1368,1376,1381,1428,1449,1511,1516,1546,1557,1587,1593,1604,1639,1645,1659,1665,1678,1706,1711,1717,1729,1769,1775,1787,1792,1851,1857,1922,1928,1934,1947,1951,2037,2068,2080,2111,2117,2129,2158,2164,2169,2175,2187,2193,2212,2222,2248,2254,2273,2310,2330,2339,2344,2353,2366,2372,2385,2390,2418,2431,2444,2453,2458,2492,2497,2523,2529,2534,2601,2668,2674,2679,2703,2749,2782,2800,2826,2875,2923,2931,3124,3130,3262,3268,3274,3453,3459,3464,3518,3523,3532,3537,3550,3556,3561,3570,3589,3598,3653,3680,3685,3690,3696,3702,3714,3741,3748,3759,3806,3812,3823,3870,3895,3901,3906,3912,3917,4224,4230,4235],{"type":35,"tag":36,"props":37,"children":38},"element","p",{},[39,42,49],{"type":40,"value":41},"text","Before doing any work, use TaskCreate to create one task for each\n",{"type":35,"tag":43,"props":44,"children":46},"code",{"className":45},[],[47],{"type":40,"value":48},"**Task:**",{"type":40,"value":50}," entry listed below. Then execute them in order, marking\neach in_progress when you start it and completed when you finish.",{"type":35,"tag":52,"props":53,"children":55},"h2",{"id":54},"inference-tasks-execute-in-order",[56],{"type":40,"value":57},"Inference Tasks — Execute In Order",{"type":35,"tag":36,"props":59,"children":60},{},[61,67,69,75,77,83],{"type":35,"tag":62,"props":63,"children":64},"strong",{},[65],{"type":40,"value":66},"Skip test functions.",{"type":40,"value":68}," Do not infer specs for ",{"type":35,"tag":43,"props":70,"children":72},{"className":71},[],[73],{"type":40,"value":74},"#[test]",{"type":40,"value":76}," or ",{"type":35,"tag":43,"props":78,"children":80},{"className":79},[],[81],{"type":40,"value":82},"#[test_only]",{"type":40,"value":84},"\nfunctions — the WP tool also skips them automatically.",{"type":35,"tag":36,"props":86,"children":87},{},[88,93,95,101,103,109,111,117,119,125,127,133],{"type":35,"tag":62,"props":89,"children":90},{},[91],{"type":40,"value":92},"Task: Synthesize loop invariants.",{"type":40,"value":94}," For every loop lacking an invariant in a\nfunction matching the ",{"type":35,"tag":43,"props":96,"children":98},{"className":97},[],[99],{"type":40,"value":100},"filter",{"type":40,"value":102},", add one marked as ",{"type":35,"tag":43,"props":104,"children":106},{"className":105},[],[107],{"type":40,"value":108},"[inferred]",{"type":40,"value":110},". Define\nrecursive spec helper functions as needed. Avoid the Common Pitfalls\ndescribed in the reference material below.\nWhen using ",{"type":35,"tag":43,"props":112,"children":114},{"className":113},[],[115],{"type":40,"value":116},"spec_output: \"file\"",{"type":40,"value":118},", add loop invariants directly in the source\n(they must stay inside the function body), but place any new spec helper\nfunctions and lemmas in the ",{"type":35,"tag":43,"props":120,"children":122},{"className":121},[],[123],{"type":40,"value":124},".spec.move",{"type":40,"value":126}," file inside a ",{"type":35,"tag":43,"props":128,"children":130},{"className":129},[],[131],{"type":40,"value":132},"spec module { }",{"type":40,"value":134}," block.",{"type":35,"tag":36,"props":136,"children":137},{},[138,143,145,150],{"type":35,"tag":62,"props":139,"children":140},{},[141],{"type":40,"value":142},"Task: Infer weakest preconditions.",{"type":40,"value":144}," With invariants in place, run the WP tool with the ",{"type":35,"tag":43,"props":146,"children":148},{"className":147},[],[149],{"type":40,"value":100},{"type":40,"value":151},".\nLet the WP tool generate the specs — do not write them by hand.",{"type":35,"tag":36,"props":153,"children":154},{},[155,160,162,168,170,176,178,183,185,190,192,197,198,203,205,211],{"type":35,"tag":62,"props":156,"children":157},{},[158],{"type":40,"value":159},"Task: Simplify inferred specs.",{"type":40,"value":161}," Apply the simplification rules from the\nreference material below. Every function must keep both ",{"type":35,"tag":43,"props":163,"children":165},{"className":164},[],[166],{"type":40,"value":167},"ensures",{"type":40,"value":169}," and\n",{"type":35,"tag":43,"props":171,"children":173},{"className":172},[],[174],{"type":40,"value":175},"aborts_if",{"type":40,"value":177}," conditions — do not drop ",{"type":35,"tag":43,"props":179,"children":181},{"className":180},[],[182],{"type":40,"value":175},{"type":40,"value":184}," just because it is hard\nto verify.\nWhen using ",{"type":35,"tag":43,"props":186,"children":188},{"className":187},[],[189],{"type":40,"value":116},{"type":40,"value":191},", all inferred spec helper functions and\nlemmas belong in the ",{"type":35,"tag":43,"props":193,"children":195},{"className":194},[],[196],{"type":40,"value":124},{"type":40,"value":126},{"type":35,"tag":43,"props":199,"children":201},{"className":200},[],[202],{"type":40,"value":132},{"type":40,"value":204}," block,\nand function conditions go in ",{"type":35,"tag":43,"props":206,"children":208},{"className":207},[],[209],{"type":40,"value":210},"spec fun_name { }",{"type":40,"value":212}," blocks in the same file.",{"type":35,"tag":52,"props":214,"children":216},{"id":215},"verification-tasks-execute-in-order",[217],{"type":40,"value":218},"Verification Tasks — Execute In Order",{"type":35,"tag":36,"props":220,"children":221},{},[222,227,229,235],{"type":35,"tag":62,"props":223,"children":224},{},[225],{"type":40,"value":226},"Task: Full-scope verification run.",{"type":40,"value":228}," Run verification for the full requested scope\nwith ",{"type":35,"tag":43,"props":230,"children":232},{"className":231},[],[233],{"type":40,"value":234},"timeout",{"type":40,"value":236}," set to 5. This gives an\noverview of all failures — both logical errors and timeouts.",{"type":35,"tag":36,"props":238,"children":239},{},[240,245,247,253],{"type":35,"tag":62,"props":241,"children":242},{},[243],{"type":40,"value":244},"Task: Fix logical errors.",{"type":40,"value":246}," If there are any logical errors, iterate to fix them\nusing the ",{"type":35,"tag":43,"props":248,"children":250},{"className":249},[],[251],{"type":40,"value":252},"exclude",{"type":40,"value":254}," parameter of the verify tool to exclude functions whose\nverification timed out. Only continue once all non-timeouts cleanly pass.",{"type":35,"tag":36,"props":256,"children":257},{},[258,263,265,270,272,278,280,286,288,294],{"type":35,"tag":62,"props":259,"children":260},{},[261],{"type":40,"value":262},"Task: Resolve timeouts.",{"type":40,"value":264}," Resolve timeouts one by one calling the prover with a\nfunction-level filter and ",{"type":35,"tag":43,"props":266,"children":268},{"className":267},[],[269],{"type":40,"value":234},{"type":40,"value":271}," set to 10.\nApply the timeout resolution strategies from the reference material below\n(spec helpers, lemmas, proofs). If a function cannot be resolved after\n2 attempts and the user did not request\notherwise, add ",{"type":35,"tag":43,"props":273,"children":275},{"className":274},[],[276],{"type":40,"value":277},"pragma verify_duration_estimate = N;",{"type":40,"value":279}," where ",{"type":35,"tag":43,"props":281,"children":283},{"className":282},[],[284],{"type":40,"value":285},"N",{"type":40,"value":287}," is the exact\ntimeout at which you observed verification succeed. If verification never\nsucceeded, use ",{"type":35,"tag":43,"props":289,"children":291},{"className":290},[],[292],{"type":40,"value":293},"pragma verify = false;",{"type":40,"value":295}," instead.",{"type":35,"tag":36,"props":297,"children":298},{},[299,304,306,311,313,318,319,324],{"type":35,"tag":62,"props":300,"children":301},{},[302],{"type":40,"value":303},"Task: Final full-scope verification.",{"type":40,"value":305}," Run the prover for the full requested scope\nusing ",{"type":35,"tag":43,"props":307,"children":309},{"className":308},[],[310],{"type":40,"value":234},{"type":40,"value":312}," 10 to verify success. Functions\nwith ",{"type":35,"tag":43,"props":314,"children":316},{"className":315},[],[317],{"type":40,"value":277},{"type":40,"value":279},{"type":35,"tag":43,"props":320,"children":322},{"className":321},[],[323],{"type":40,"value":285},{"type":40,"value":325}," exceeds the timeout will\nbe automatically skipped — this is expected.",{"type":35,"tag":36,"props":327,"children":328},{},[329],{"type":40,"value":330},"The reference material below supports the tasks above.",{"type":35,"tag":52,"props":332,"children":334},{"id":333},"move-specification-language",[335],{"type":40,"value":336},"Move Specification Language",{"type":35,"tag":36,"props":338,"children":339},{},[340,342,348],{"type":40,"value":341},"Move specifications use ",{"type":35,"tag":43,"props":343,"children":345},{"className":344},[],[346],{"type":40,"value":347},"spec",{"type":40,"value":349}," blocks to express formal properties that are checked\nby the Move Prover.",{"type":35,"tag":351,"props":352,"children":354},"h3",{"id":353},"function-spec-clauses",[355],{"type":40,"value":356},"Function spec clauses",{"type":35,"tag":36,"props":358,"children":359},{},[360,362,368,370,376,378,384,386,392],{"type":40,"value":361},"These appear in ",{"type":35,"tag":43,"props":363,"children":365},{"className":364},[],[366],{"type":40,"value":367},"spec fun_name { ... }",{"type":40,"value":369}," blocks. Spec blocks always appear after the function\ndefinition. If ",{"type":35,"tag":43,"props":371,"children":373},{"className":372},[],[374],{"type":40,"value":375},"fun_name",{"type":40,"value":377}," clashes with a soft keyword (e.g. ",{"type":35,"tag":43,"props":379,"children":381},{"className":380},[],[382],{"type":40,"value":383},"lemma",{"type":40,"value":385},"), use ",{"type":35,"tag":43,"props":387,"children":389},{"className":388},[],[390],{"type":40,"value":391},"spec @fun_name { ... }",{"type":40,"value":393},"\nto escape it.",{"type":35,"tag":395,"props":396,"children":397},"ul",{},[398,425,488,519],{"type":35,"tag":399,"props":400,"children":401},"li",{},[402,408,410,415,417,423],{"type":35,"tag":43,"props":403,"children":405},{"className":404},[],[406],{"type":40,"value":407},"ensures \u003Cexpr>",{"type":40,"value":409},": Postcondition that must hold when the function returns normally.\nEvaluated in the ",{"type":35,"tag":62,"props":411,"children":412},{},[413],{"type":40,"value":414},"post-state",{"type":40,"value":416},". Use ",{"type":35,"tag":43,"props":418,"children":420},{"className":419},[],[421],{"type":40,"value":422},"old(expr)",{"type":40,"value":424}," to refer to pre-state values.",{"type":35,"tag":399,"props":426,"children":427},{},[428,434,436,441,443,449,451,456,458,463,465,470,472,478,480,486],{"type":35,"tag":43,"props":429,"children":431},{"className":430},[],[432],{"type":40,"value":433},"aborts_if \u003Cexpr>",{"type":40,"value":435},": Condition under which the function may abort. ",{"type":35,"tag":62,"props":437,"children":438},{},[439],{"type":40,"value":440},"Evaluated in the\npre-state",{"type":40,"value":442}," — do not use ",{"type":35,"tag":43,"props":444,"children":446},{"className":445},[],[447],{"type":40,"value":448},"old()",{"type":40,"value":450}," (see ",{"type":35,"tag":43,"props":452,"children":454},{"className":453},[],[455],{"type":40,"value":448},{"type":40,"value":457}," usage rules below). If any\n",{"type":35,"tag":43,"props":459,"children":461},{"className":460},[],[462],{"type":40,"value":175},{"type":40,"value":464}," conditions are present, the function must abort if and only if one of the\nconditions holds. Omitting all ",{"type":35,"tag":43,"props":466,"children":468},{"className":467},[],[469],{"type":40,"value":175},{"type":40,"value":471}," clauses means abort behavior is ",{"type":35,"tag":473,"props":474,"children":475},"em",{},[476],{"type":40,"value":477},"unspecified",{"type":40,"value":479},"\n(any abort is allowed). To express that a function never aborts, write ",{"type":35,"tag":43,"props":481,"children":483},{"className":482},[],[484],{"type":40,"value":485},"aborts_if false;",{"type":40,"value":487},".",{"type":35,"tag":399,"props":489,"children":490},{},[491,497,499,504,506,511,512,517],{"type":35,"tag":43,"props":492,"children":494},{"className":493},[],[495],{"type":40,"value":496},"requires \u003Cexpr>",{"type":40,"value":498},": Precondition that callers must satisfy. ",{"type":35,"tag":62,"props":500,"children":501},{},[502],{"type":40,"value":503},"Evaluated in the pre-state",{"type":40,"value":505}," —\nDo not use ",{"type":35,"tag":43,"props":507,"children":509},{"className":508},[],[510],{"type":40,"value":448},{"type":40,"value":450},{"type":35,"tag":43,"props":513,"children":515},{"className":514},[],[516],{"type":40,"value":448},{"type":40,"value":518}," usage rules below).",{"type":35,"tag":399,"props":520,"children":521},{},[522,528],{"type":35,"tag":43,"props":523,"children":525},{"className":524},[],[526],{"type":40,"value":527},"modifies \u003Cresource>",{"type":40,"value":529},": Declares which global resources the function may modify.",{"type":35,"tag":351,"props":531,"children":533},{"id":532},"loop-invariants",[534],{"type":40,"value":535},"Loop invariants",{"type":35,"tag":36,"props":537,"children":538},{},[539,541,546],{"type":40,"value":540},"Loop invariants appear in a ",{"type":35,"tag":43,"props":542,"children":544},{"className":543},[],[545],{"type":40,"value":347},{"type":40,"value":547}," block after the loop body:",{"type":35,"tag":549,"props":550,"children":555},"pre",{"className":551,"code":552,"language":553,"meta":554,"style":554},"language-move shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","while (cond) {\n    \u002F\u002F body\n} spec {\n    invariant \u003Cexpr>;\n};\n","move","",[556],{"type":35,"tag":43,"props":557,"children":558},{"__ignoreMap":554},[559,570,579,588,597],{"type":35,"tag":560,"props":561,"children":564},"span",{"class":562,"line":563},"line",1,[565],{"type":35,"tag":560,"props":566,"children":567},{},[568],{"type":40,"value":569},"while (cond) {\n",{"type":35,"tag":560,"props":571,"children":573},{"class":562,"line":572},2,[574],{"type":35,"tag":560,"props":575,"children":576},{},[577],{"type":40,"value":578},"    \u002F\u002F body\n",{"type":35,"tag":560,"props":580,"children":582},{"class":562,"line":581},3,[583],{"type":35,"tag":560,"props":584,"children":585},{},[586],{"type":40,"value":587},"} spec {\n",{"type":35,"tag":560,"props":589,"children":591},{"class":562,"line":590},4,[592],{"type":35,"tag":560,"props":593,"children":594},{},[595],{"type":40,"value":596},"    invariant \u003Cexpr>;\n",{"type":35,"tag":560,"props":598,"children":600},{"class":562,"line":599},5,[601],{"type":35,"tag":560,"props":602,"children":603},{},[604],{"type":40,"value":605},"};\n",{"type":35,"tag":395,"props":607,"children":608},{},[609],{"type":35,"tag":399,"props":610,"children":611},{},[612,618,620,626,628,633],{"type":35,"tag":43,"props":613,"children":615},{"className":614},[],[616],{"type":40,"value":617},"invariant \u003Cexpr>",{"type":40,"value":619},": A property that holds before the first iteration and is preserved by\neach iteration. ",{"type":35,"tag":43,"props":621,"children":623},{"className":622},[],[624],{"type":40,"value":625},"old(x)",{"type":40,"value":627}," is only allowed on function parameters (see ",{"type":35,"tag":43,"props":629,"children":631},{"className":630},[],[632],{"type":40,"value":448},{"type":40,"value":634}," usage rules below.)",{"type":35,"tag":36,"props":636,"children":637},{},[638,640,645,647,653],{"type":40,"value":639},"Loops without invariants cause the prover to ",{"type":35,"tag":473,"props":641,"children":642},{},[643],{"type":40,"value":644},"havoc",{"type":40,"value":646}," all loop-modified variables, which can\nproduce vacuous, incorrect, or overly weak specifications. Every loop needs an invariant —\nexamine the actual ",{"type":35,"tag":43,"props":648,"children":650},{"className":649},[],[651],{"type":40,"value":652},"while",{"type":40,"value":654}," loops in function bodies to find all loops that lack one.",{"type":35,"tag":36,"props":656,"children":657},{},[658],{"type":40,"value":659},"A good invariant:",{"type":35,"tag":661,"props":662,"children":663},"ol",{},[664,669,674],{"type":35,"tag":399,"props":665,"children":666},{},[667],{"type":40,"value":668},"Holds before the first iteration (initial values satisfy it).",{"type":35,"tag":399,"props":670,"children":671},{},[672],{"type":40,"value":673},"Is preserved by each iteration (inductive step).",{"type":35,"tag":399,"props":675,"children":676},{},[677,679,685,687,693],{"type":40,"value":678},"Relates loop-modified variables to function parameters and constants\n(e.g., bounds like ",{"type":35,"tag":43,"props":680,"children":682},{"className":681},[],[683],{"type":40,"value":684},"i \u003C= n",{"type":40,"value":686},", accumulators like ",{"type":35,"tag":43,"props":688,"children":690},{"className":689},[],[691],{"type":40,"value":692},"sum == i * step",{"type":40,"value":694},").",{"type":35,"tag":351,"props":696,"children":698},{"id":697},"expressions-in-specs",[699],{"type":40,"value":700},"Expressions in specs",{"type":35,"tag":395,"props":702,"children":703},{},[704,729,746,772,796,844],{"type":35,"tag":399,"props":705,"children":706},{},[707,712,714,720,722,727],{"type":35,"tag":43,"props":708,"children":710},{"className":709},[],[711],{"type":40,"value":422},{"type":40,"value":713},": Value of ",{"type":35,"tag":43,"props":715,"children":717},{"className":716},[],[718],{"type":40,"value":719},"expr",{"type":40,"value":721}," at function entry. See ",{"type":35,"tag":43,"props":723,"children":725},{"className":724},[],[726],{"type":40,"value":448},{"type":40,"value":728}," usage rules below for\nwhere this is allowed.",{"type":35,"tag":399,"props":730,"children":731},{},[732,738,740,745],{"type":35,"tag":43,"props":733,"children":735},{"className":734},[],[736],{"type":40,"value":737},"result",{"type":40,"value":739},": Return value. Only valid in ",{"type":35,"tag":43,"props":741,"children":743},{"className":742},[],[744],{"type":40,"value":167},{"type":40,"value":487},{"type":35,"tag":399,"props":747,"children":748},{},[749,755,757,763,765,771],{"type":35,"tag":43,"props":750,"children":752},{"className":751},[],[753],{"type":40,"value":754},"global\u003CT>(addr)",{"type":40,"value":756},": Global resource of type ",{"type":35,"tag":43,"props":758,"children":760},{"className":759},[],[761],{"type":40,"value":762},"T",{"type":40,"value":764}," at address ",{"type":35,"tag":43,"props":766,"children":768},{"className":767},[],[769],{"type":40,"value":770},"addr",{"type":40,"value":487},{"type":35,"tag":399,"props":773,"children":774},{},[775,781,783,788,790,795],{"type":35,"tag":43,"props":776,"children":778},{"className":777},[],[779],{"type":40,"value":780},"exists\u003CT>(addr)",{"type":40,"value":782},": True if a resource of type ",{"type":35,"tag":43,"props":784,"children":786},{"className":785},[],[787],{"type":40,"value":762},{"type":40,"value":789}," exists at address ",{"type":35,"tag":43,"props":791,"children":793},{"className":792},[],[794],{"type":40,"value":770},{"type":40,"value":487},{"type":35,"tag":399,"props":797,"children":798},{},[799,801,807,809,815,816,822,823,829,830,836,837,843],{"type":40,"value":800},"Numeric type bounds: ",{"type":35,"tag":43,"props":802,"children":804},{"className":803},[],[805],{"type":40,"value":806},"MAX_U8",{"type":40,"value":808},", ",{"type":35,"tag":43,"props":810,"children":812},{"className":811},[],[813],{"type":40,"value":814},"MAX_U16",{"type":40,"value":808},{"type":35,"tag":43,"props":817,"children":819},{"className":818},[],[820],{"type":40,"value":821},"MAX_U32",{"type":40,"value":808},{"type":35,"tag":43,"props":824,"children":826},{"className":825},[],[827],{"type":40,"value":828},"MAX_U64",{"type":40,"value":808},{"type":35,"tag":43,"props":831,"children":833},{"className":832},[],[834],{"type":40,"value":835},"MAX_U128",{"type":40,"value":808},{"type":35,"tag":43,"props":838,"children":840},{"className":839},[],[841],{"type":40,"value":842},"MAX_U256",{"type":40,"value":487},{"type":35,"tag":399,"props":845,"children":846},{},[847,852,854,860,862,868,870,876,878,884,885,891],{"type":35,"tag":62,"props":848,"children":849},{},[850],{"type":40,"value":851},"No dereference or borrow",{"type":40,"value":853},": ",{"type":35,"tag":43,"props":855,"children":857},{"className":856},[],[858],{"type":40,"value":859},"*e",{"type":40,"value":861}," and ",{"type":35,"tag":43,"props":863,"children":865},{"className":864},[],[866],{"type":40,"value":867},"&e",{"type":40,"value":869}," are not allowed in spec\nexpressions. Spec expressions operate on values, not references — access\nfields directly (e.g. ",{"type":35,"tag":43,"props":871,"children":873},{"className":872},[],[874],{"type":40,"value":875},"v.field",{"type":40,"value":877},", not ",{"type":35,"tag":43,"props":879,"children":881},{"className":880},[],[882],{"type":40,"value":883},"(*v).field",{"type":40,"value":76},{"type":35,"tag":43,"props":886,"children":888},{"className":887},[],[889],{"type":40,"value":890},"(&v).field",{"type":40,"value":694},{"type":35,"tag":351,"props":893,"children":895},{"id":894},"old-usage-rules",[896,901],{"type":35,"tag":43,"props":897,"children":899},{"className":898},[],[900],{"type":40,"value":448},{"type":40,"value":902}," usage rules",{"type":35,"tag":36,"props":904,"children":905},{},[906,911,913,918],{"type":35,"tag":43,"props":907,"children":909},{"className":908},[],[910],{"type":40,"value":422},{"type":40,"value":912}," means \"value of ",{"type":35,"tag":43,"props":914,"children":916},{"className":915},[],[917],{"type":40,"value":719},{"type":40,"value":919}," at function entry.\" It is only valid in specific contexts:",{"type":35,"tag":36,"props":921,"children":922},{},[923],{"type":35,"tag":62,"props":924,"children":925},{},[926],{"type":40,"value":927},"Wrong \u002F Right examples:",{"type":35,"tag":549,"props":929,"children":931},{"className":551,"code":930,"language":553,"meta":554,"style":554},"\u002F\u002F WRONG: old() in aborts_if — compilation error\naborts_if old(x) + old(y) > MAX_U64;\n\u002F\u002F RIGHT: aborts_if is pre-state, just use the variables directly\naborts_if x + y > MAX_U64;\n\n\u002F\u002F WRONG: old() in requires — compilation error\nrequires old(len(v)) > 0;\n\u002F\u002F RIGHT: requires is pre-state\nrequires len(v) > 0;\n\n\u002F\u002F WRONG: old(local) in loop invariant — compilation error\ninvariant old(sum) \u003C= old(n) * MAX_U64;\n\u002F\u002F RIGHT: sum is a local — use it directly; n is a parameter — old(n) is ok\ninvariant sum \u003C= old(n) * MAX_U64;\n\n\u002F\u002F WRONG: old(resource) in loop invariant — compilation error\ninvariant old(global\u003CT>(addr)).field == 0;\n\u002F\u002F RIGHT: use resource directly\ninvariant global\u003CT>(addr).field == 0;\n",[932],{"type":35,"tag":43,"props":933,"children":934},{"__ignoreMap":554},[935,943,951,959,967,976,985,994,1003,1012,1020,1029,1038,1047,1056,1064,1073,1082,1091],{"type":35,"tag":560,"props":936,"children":937},{"class":562,"line":563},[938],{"type":35,"tag":560,"props":939,"children":940},{},[941],{"type":40,"value":942},"\u002F\u002F WRONG: old() in aborts_if — compilation error\n",{"type":35,"tag":560,"props":944,"children":945},{"class":562,"line":572},[946],{"type":35,"tag":560,"props":947,"children":948},{},[949],{"type":40,"value":950},"aborts_if old(x) + old(y) > MAX_U64;\n",{"type":35,"tag":560,"props":952,"children":953},{"class":562,"line":581},[954],{"type":35,"tag":560,"props":955,"children":956},{},[957],{"type":40,"value":958},"\u002F\u002F RIGHT: aborts_if is pre-state, just use the variables directly\n",{"type":35,"tag":560,"props":960,"children":961},{"class":562,"line":590},[962],{"type":35,"tag":560,"props":963,"children":964},{},[965],{"type":40,"value":966},"aborts_if x + y > MAX_U64;\n",{"type":35,"tag":560,"props":968,"children":969},{"class":562,"line":599},[970],{"type":35,"tag":560,"props":971,"children":973},{"emptyLinePlaceholder":972},true,[974],{"type":40,"value":975},"\n",{"type":35,"tag":560,"props":977,"children":979},{"class":562,"line":978},6,[980],{"type":35,"tag":560,"props":981,"children":982},{},[983],{"type":40,"value":984},"\u002F\u002F WRONG: old() in requires — compilation error\n",{"type":35,"tag":560,"props":986,"children":988},{"class":562,"line":987},7,[989],{"type":35,"tag":560,"props":990,"children":991},{},[992],{"type":40,"value":993},"requires old(len(v)) > 0;\n",{"type":35,"tag":560,"props":995,"children":997},{"class":562,"line":996},8,[998],{"type":35,"tag":560,"props":999,"children":1000},{},[1001],{"type":40,"value":1002},"\u002F\u002F RIGHT: requires is pre-state\n",{"type":35,"tag":560,"props":1004,"children":1006},{"class":562,"line":1005},9,[1007],{"type":35,"tag":560,"props":1008,"children":1009},{},[1010],{"type":40,"value":1011},"requires len(v) > 0;\n",{"type":35,"tag":560,"props":1013,"children":1015},{"class":562,"line":1014},10,[1016],{"type":35,"tag":560,"props":1017,"children":1018},{"emptyLinePlaceholder":972},[1019],{"type":40,"value":975},{"type":35,"tag":560,"props":1021,"children":1023},{"class":562,"line":1022},11,[1024],{"type":35,"tag":560,"props":1025,"children":1026},{},[1027],{"type":40,"value":1028},"\u002F\u002F WRONG: old(local) in loop invariant — compilation error\n",{"type":35,"tag":560,"props":1030,"children":1032},{"class":562,"line":1031},12,[1033],{"type":35,"tag":560,"props":1034,"children":1035},{},[1036],{"type":40,"value":1037},"invariant old(sum) \u003C= old(n) * MAX_U64;\n",{"type":35,"tag":560,"props":1039,"children":1041},{"class":562,"line":1040},13,[1042],{"type":35,"tag":560,"props":1043,"children":1044},{},[1045],{"type":40,"value":1046},"\u002F\u002F RIGHT: sum is a local — use it directly; n is a parameter — old(n) is ok\n",{"type":35,"tag":560,"props":1048,"children":1050},{"class":562,"line":1049},14,[1051],{"type":35,"tag":560,"props":1052,"children":1053},{},[1054],{"type":40,"value":1055},"invariant sum \u003C= old(n) * MAX_U64;\n",{"type":35,"tag":560,"props":1057,"children":1059},{"class":562,"line":1058},15,[1060],{"type":35,"tag":560,"props":1061,"children":1062},{"emptyLinePlaceholder":972},[1063],{"type":40,"value":975},{"type":35,"tag":560,"props":1065,"children":1067},{"class":562,"line":1066},16,[1068],{"type":35,"tag":560,"props":1069,"children":1070},{},[1071],{"type":40,"value":1072},"\u002F\u002F WRONG: old(resource) in loop invariant — compilation error\n",{"type":35,"tag":560,"props":1074,"children":1076},{"class":562,"line":1075},17,[1077],{"type":35,"tag":560,"props":1078,"children":1079},{},[1080],{"type":40,"value":1081},"invariant old(global\u003CT>(addr)).field == 0;\n",{"type":35,"tag":560,"props":1083,"children":1085},{"class":562,"line":1084},18,[1086],{"type":35,"tag":560,"props":1087,"children":1088},{},[1089],{"type":40,"value":1090},"\u002F\u002F RIGHT: use resource directly\n",{"type":35,"tag":560,"props":1092,"children":1094},{"class":562,"line":1093},19,[1095],{"type":35,"tag":560,"props":1096,"children":1097},{},[1098],{"type":40,"value":1099},"invariant global\u003CT>(addr).field == 0;\n",{"type":35,"tag":351,"props":1101,"children":1103},{"id":1102},"referring-to-behavior-of-other-functions",[1104],{"type":40,"value":1105},"Referring to Behavior of other Functions",{"type":35,"tag":36,"props":1107,"children":1108},{},[1109,1111,1116,1118,1123],{"type":40,"value":1110},"When specifying a function that calls other functions ",{"type":35,"tag":62,"props":1112,"children":1113},{},[1114],{"type":40,"value":1115},"which are not inline functions",{"type":40,"value":1117},", you\ncan use ",{"type":35,"tag":62,"props":1119,"children":1120},{},[1121],{"type":40,"value":1122},"behavioral predicates",{"type":40,"value":1124}," to abstract the callee's specification without inlining its\ndetails. These built-in predicates lift a function's spec clauses into expressions:",{"type":35,"tag":395,"props":1126,"children":1127},{},[1128,1162,1190,1234],{"type":35,"tag":399,"props":1129,"children":1130},{},[1131,1137,1139,1145,1147,1153,1155,1161],{"type":35,"tag":43,"props":1132,"children":1134},{"className":1133},[],[1135],{"type":40,"value":1136},"requires_of\u003Cf>(args)",{"type":40,"value":1138}," — true when ",{"type":35,"tag":43,"props":1140,"children":1142},{"className":1141},[],[1143],{"type":40,"value":1144},"f",{"type":40,"value":1146},"'s ",{"type":35,"tag":43,"props":1148,"children":1150},{"className":1149},[],[1151],{"type":40,"value":1152},"requires",{"type":40,"value":1154}," clauses hold for ",{"type":35,"tag":43,"props":1156,"children":1158},{"className":1157},[],[1159],{"type":40,"value":1160},"args",{"type":40,"value":487},{"type":35,"tag":399,"props":1163,"children":1164},{},[1165,1171,1172,1177,1178,1183,1184,1189],{"type":35,"tag":43,"props":1166,"children":1168},{"className":1167},[],[1169],{"type":40,"value":1170},"aborts_of\u003Cf>(args)",{"type":40,"value":1138},{"type":35,"tag":43,"props":1173,"children":1175},{"className":1174},[],[1176],{"type":40,"value":1144},{"type":40,"value":1146},{"type":35,"tag":43,"props":1179,"children":1181},{"className":1180},[],[1182],{"type":40,"value":175},{"type":40,"value":1154},{"type":35,"tag":43,"props":1185,"children":1187},{"className":1186},[],[1188],{"type":40,"value":1160},{"type":40,"value":487},{"type":35,"tag":399,"props":1191,"children":1192},{},[1193,1199,1200,1205,1206,1211,1213,1218,1220,1225,1227,1233],{"type":35,"tag":43,"props":1194,"children":1196},{"className":1195},[],[1197],{"type":40,"value":1198},"ensures_of\u003Cf>(args, result)",{"type":40,"value":1138},{"type":35,"tag":43,"props":1201,"children":1203},{"className":1202},[],[1204],{"type":40,"value":1144},{"type":40,"value":1146},{"type":35,"tag":43,"props":1207,"children":1209},{"className":1208},[],[1210],{"type":40,"value":167},{"type":40,"value":1212}," clauses hold for\n",{"type":35,"tag":43,"props":1214,"children":1216},{"className":1215},[],[1217],{"type":40,"value":1160},{"type":40,"value":1219}," and the given ",{"type":35,"tag":43,"props":1221,"children":1223},{"className":1222},[],[1224],{"type":40,"value":737},{"type":40,"value":1226}," value(s). For functions returning unit, omit\nthe result argument. For multiple return values, pass ",{"type":35,"tag":43,"props":1228,"children":1230},{"className":1229},[],[1231],{"type":40,"value":1232},"result_1, result_2, ...",{"type":40,"value":487},{"type":35,"tag":399,"props":1235,"children":1236},{},[1237,1243,1245,1250,1252,1257,1259,1265],{"type":35,"tag":43,"props":1238,"children":1240},{"className":1239},[],[1241],{"type":40,"value":1242},"result_of\u003Cf>(args)",{"type":40,"value":1244}," — the return value of ",{"type":35,"tag":43,"props":1246,"children":1248},{"className":1247},[],[1249],{"type":40,"value":1144},{"type":40,"value":1251}," when called with ",{"type":35,"tag":43,"props":1253,"children":1255},{"className":1254},[],[1256],{"type":40,"value":1160},{"type":40,"value":1258},",\nusable in ",{"type":35,"tag":43,"props":1260,"children":1262},{"className":1261},[],[1263],{"type":40,"value":1264},"let",{"type":40,"value":1266}," bindings and expressions inside spec blocks.",{"type":35,"tag":36,"props":1268,"children":1269},{},[1270,1272,1278],{"type":40,"value":1271},"The ",{"type":35,"tag":43,"props":1273,"children":1275},{"className":1274},[],[1276],{"type":40,"value":1277},"\u003Cf>",{"type":40,"value":1279}," target can be:",{"type":35,"tag":395,"props":1281,"children":1282},{},[1283,1317,1343],{"type":35,"tag":399,"props":1284,"children":1285},{},[1286,1288,1293,1295,1301,1303,1308,1310,1316],{"type":40,"value":1287},"A ",{"type":35,"tag":62,"props":1289,"children":1290},{},[1291],{"type":40,"value":1292},"function parameter",{"type":40,"value":1294}," of function type: ",{"type":35,"tag":43,"props":1296,"children":1298},{"className":1297},[],[1299],{"type":40,"value":1300},"ensures_of\u003Cf>(x, result)",{"type":40,"value":1302}," where\n",{"type":35,"tag":43,"props":1304,"children":1306},{"className":1305},[],[1307],{"type":40,"value":1144},{"type":40,"value":1309}," is a parameter with type ",{"type":35,"tag":43,"props":1311,"children":1313},{"className":1312},[],[1314],{"type":40,"value":1315},"|u64| u64",{"type":40,"value":487},{"type":35,"tag":399,"props":1318,"children":1319},{},[1320,1321,1326,1328,1334,1336,1342],{"type":40,"value":1287},{"type":35,"tag":62,"props":1322,"children":1323},{},[1324],{"type":40,"value":1325},"named function",{"type":40,"value":1327}," (same module or cross-module): ",{"type":35,"tag":43,"props":1329,"children":1331},{"className":1330},[],[1332],{"type":40,"value":1333},"ensures_of\u003Cincrement>(x, result)",{"type":40,"value":1335},"\nor ",{"type":35,"tag":43,"props":1337,"children":1339},{"className":1338},[],[1340],{"type":40,"value":1341},"ensures_of\u003CM::increment>(x, result)",{"type":40,"value":487},{"type":35,"tag":399,"props":1344,"children":1345},{},[1346,1347,1352,1354,1360,1361,1367],{"type":40,"value":1287},{"type":35,"tag":62,"props":1348,"children":1349},{},[1350],{"type":40,"value":1351},"generic function",{"type":40,"value":1353}," with explicit or inferred type arguments:\n",{"type":35,"tag":43,"props":1355,"children":1357},{"className":1356},[],[1358],{"type":40,"value":1359},"ensures_of\u003Cidentity\u003Cu64>>(x, result)",{"type":40,"value":76},{"type":35,"tag":43,"props":1362,"children":1364},{"className":1363},[],[1365],{"type":40,"value":1366},"ensures_of\u003Cidentity>(x, result)",{"type":40,"value":487},{"type":35,"tag":36,"props":1369,"children":1370},{},[1371],{"type":35,"tag":62,"props":1372,"children":1373},{},[1374],{"type":40,"value":1375},"Examples:",{"type":35,"tag":36,"props":1377,"children":1378},{},[1379],{"type":40,"value":1380},"Specifying a higher-order function that applies a callback:",{"type":35,"tag":549,"props":1382,"children":1384},{"className":551,"code":1383,"language":553,"meta":554,"style":554},"fun apply(f: |u64| u64, x: u64): u64 { f(x) }\nspec apply {\n    aborts_if aborts_of\u003Cf>(x);\n    ensures ensures_of\u003Cf>(x, result);\n}\n",[1385],{"type":35,"tag":43,"props":1386,"children":1387},{"__ignoreMap":554},[1388,1396,1404,1412,1420],{"type":35,"tag":560,"props":1389,"children":1390},{"class":562,"line":563},[1391],{"type":35,"tag":560,"props":1392,"children":1393},{},[1394],{"type":40,"value":1395},"fun apply(f: |u64| u64, x: u64): u64 { f(x) }\n",{"type":35,"tag":560,"props":1397,"children":1398},{"class":562,"line":572},[1399],{"type":35,"tag":560,"props":1400,"children":1401},{},[1402],{"type":40,"value":1403},"spec apply {\n",{"type":35,"tag":560,"props":1405,"children":1406},{"class":562,"line":581},[1407],{"type":35,"tag":560,"props":1408,"children":1409},{},[1410],{"type":40,"value":1411},"    aborts_if aborts_of\u003Cf>(x);\n",{"type":35,"tag":560,"props":1413,"children":1414},{"class":562,"line":590},[1415],{"type":35,"tag":560,"props":1416,"children":1417},{},[1418],{"type":40,"value":1419},"    ensures ensures_of\u003Cf>(x, result);\n",{"type":35,"tag":560,"props":1421,"children":1422},{"class":562,"line":599},[1423],{"type":35,"tag":560,"props":1424,"children":1425},{},[1426],{"type":40,"value":1427},"}\n",{"type":35,"tag":36,"props":1429,"children":1430},{},[1431,1433,1439,1441,1447],{"type":40,"value":1432},"Using ",{"type":35,"tag":43,"props":1434,"children":1436},{"className":1435},[],[1437],{"type":40,"value":1438},"result_of",{"type":40,"value":1440}," to chain calls in a spec (e.g. ",{"type":35,"tag":43,"props":1442,"children":1444},{"className":1443},[],[1445],{"type":40,"value":1446},"f(f(x))",{"type":40,"value":1448},"):",{"type":35,"tag":549,"props":1450,"children":1452},{"className":551,"code":1451,"language":553,"meta":554,"style":554},"fun apply_seq(f: |u64| u64 has copy, x: u64): u64 { f(f(x)) }\nspec apply_seq {\n    let y = result_of\u003Cf>(x);\n    requires requires_of\u003Cf>(x) && requires_of\u003Cf>(y);\n    aborts_if aborts_of\u003Cf>(x) || aborts_of\u003Cf>(y);\n    ensures result == result_of\u003Cf>(y);\n}\n",[1453],{"type":35,"tag":43,"props":1454,"children":1455},{"__ignoreMap":554},[1456,1464,1472,1480,1488,1496,1504],{"type":35,"tag":560,"props":1457,"children":1458},{"class":562,"line":563},[1459],{"type":35,"tag":560,"props":1460,"children":1461},{},[1462],{"type":40,"value":1463},"fun apply_seq(f: |u64| u64 has copy, x: u64): u64 { f(f(x)) }\n",{"type":35,"tag":560,"props":1465,"children":1466},{"class":562,"line":572},[1467],{"type":35,"tag":560,"props":1468,"children":1469},{},[1470],{"type":40,"value":1471},"spec apply_seq {\n",{"type":35,"tag":560,"props":1473,"children":1474},{"class":562,"line":581},[1475],{"type":35,"tag":560,"props":1476,"children":1477},{},[1478],{"type":40,"value":1479},"    let y = result_of\u003Cf>(x);\n",{"type":35,"tag":560,"props":1481,"children":1482},{"class":562,"line":590},[1483],{"type":35,"tag":560,"props":1484,"children":1485},{},[1486],{"type":40,"value":1487},"    requires requires_of\u003Cf>(x) && requires_of\u003Cf>(y);\n",{"type":35,"tag":560,"props":1489,"children":1490},{"class":562,"line":599},[1491],{"type":35,"tag":560,"props":1492,"children":1493},{},[1494],{"type":40,"value":1495},"    aborts_if aborts_of\u003Cf>(x) || aborts_of\u003Cf>(y);\n",{"type":35,"tag":560,"props":1497,"children":1498},{"class":562,"line":978},[1499],{"type":35,"tag":560,"props":1500,"children":1501},{},[1502],{"type":40,"value":1503},"    ensures result == result_of\u003Cf>(y);\n",{"type":35,"tag":560,"props":1505,"children":1506},{"class":562,"line":987},[1507],{"type":35,"tag":560,"props":1508,"children":1509},{},[1510],{"type":40,"value":1427},{"type":35,"tag":36,"props":1512,"children":1513},{},[1514],{"type":40,"value":1515},"Referring to a named function's behavior from a caller:",{"type":35,"tag":549,"props":1517,"children":1519},{"className":551,"code":1518,"language":553,"meta":554,"style":554},"spec bar {\n    ensures ensures_of\u003Cincrement>(x, result);\n}\n",[1520],{"type":35,"tag":43,"props":1521,"children":1522},{"__ignoreMap":554},[1523,1531,1539],{"type":35,"tag":560,"props":1524,"children":1525},{"class":562,"line":563},[1526],{"type":35,"tag":560,"props":1527,"children":1528},{},[1529],{"type":40,"value":1530},"spec bar {\n",{"type":35,"tag":560,"props":1532,"children":1533},{"class":562,"line":572},[1534],{"type":35,"tag":560,"props":1535,"children":1536},{},[1537],{"type":40,"value":1538},"    ensures ensures_of\u003Cincrement>(x, result);\n",{"type":35,"tag":560,"props":1540,"children":1541},{"class":562,"line":581},[1542],{"type":35,"tag":560,"props":1543,"children":1544},{},[1545],{"type":40,"value":1427},{"type":35,"tag":36,"props":1547,"children":1548},{},[1549,1550,1555],{"type":40,"value":1432},{"type":35,"tag":43,"props":1551,"children":1553},{"className":1552},[],[1554],{"type":40,"value":1438},{"type":40,"value":1556}," inside loop invariants with closures:",{"type":35,"tag":549,"props":1558,"children":1560},{"className":551,"code":1559,"language":553,"meta":554,"style":554},"spec {\n    invariant forall j in 0..i: !result_of\u003Cpred>(v[j]);\n};\n",[1561],{"type":35,"tag":43,"props":1562,"children":1563},{"__ignoreMap":554},[1564,1572,1580],{"type":35,"tag":560,"props":1565,"children":1566},{"class":562,"line":563},[1567],{"type":35,"tag":560,"props":1568,"children":1569},{},[1570],{"type":40,"value":1571},"spec {\n",{"type":35,"tag":560,"props":1573,"children":1574},{"class":562,"line":572},[1575],{"type":35,"tag":560,"props":1576,"children":1577},{},[1578],{"type":40,"value":1579},"    invariant forall j in 0..i: !result_of\u003Cpred>(v[j]);\n",{"type":35,"tag":560,"props":1581,"children":1582},{"class":562,"line":581},[1583],{"type":35,"tag":560,"props":1584,"children":1585},{},[1586],{"type":40,"value":605},{"type":35,"tag":351,"props":1588,"children":1590},{"id":1589},"property-markers",[1591],{"type":40,"value":1592},"Property markers",{"type":35,"tag":36,"props":1594,"children":1595},{},[1596,1597,1602],{"type":40,"value":1271},{"type":35,"tag":43,"props":1598,"children":1600},{"className":1599},[],[1601],{"type":40,"value":108},{"type":40,"value":1603}," property marks conditions that were not written by the user. Its value indicates\nthe origin or quality:",{"type":35,"tag":395,"props":1605,"children":1606},{},[1607,1617,1628],{"type":35,"tag":399,"props":1608,"children":1609},{},[1610,1615],{"type":35,"tag":43,"props":1611,"children":1613},{"className":1612},[],[1614],{"type":40,"value":108},{"type":40,"value":1616},": Automatically inferred by weakest-precondition (WP) analysis. It may be overly complex, redundant,\nor occasionally incorrect.",{"type":35,"tag":399,"props":1618,"children":1619},{},[1620,1626],{"type":35,"tag":43,"props":1621,"children":1623},{"className":1622},[],[1624],{"type":40,"value":1625},"[inferred = vacuous]",{"type":40,"value":1627},": Inferred by WP but detected as potentially vacuous (trivially true)\ndue to unconstrained quantifier variables. Typically results from missing loop invariants.",{"type":35,"tag":399,"props":1629,"children":1630},{},[1631,1637],{"type":35,"tag":43,"props":1632,"children":1634},{"className":1633},[],[1635],{"type":40,"value":1636},"[inferred = sathard]",{"type":40,"value":1638},": Inferred by WP but contains quantifier patterns that are hard for\nSMT solvers. Likely to cause verification timeouts — should be simplified or reformulated.",{"type":35,"tag":351,"props":1640,"children":1642},{"id":1641},"links",[1643],{"type":40,"value":1644},"Links",{"type":35,"tag":395,"props":1646,"children":1647},{},[1648],{"type":35,"tag":399,"props":1649,"children":1650},{},[1651],{"type":35,"tag":1652,"props":1653,"children":1657},"a",{"href":1654,"rel":1655},"https:\u002F\u002Faptos.dev\u002Fen\u002Fbuild\u002Fsmart-contracts\u002Fprover\u002Fspec-lang",[1656],"nofollow",[1658],{"type":40,"value":336},{"type":35,"tag":52,"props":1660,"children":1662},{"id":1661},"checking-move-code",[1663],{"type":40,"value":1664},"Checking Move Code",{"type":35,"tag":36,"props":1666,"children":1667},{},[1668,1670,1676],{"type":40,"value":1669},"Use the ",{"type":35,"tag":43,"props":1671,"children":1673},{"className":1672},[],[1674],{"type":40,"value":1675},"move_package_status",{"type":40,"value":1677}," MCP tool to check for compilation errors and warnings.",{"type":35,"tag":395,"props":1679,"children":1680},{},[1681,1701],{"type":35,"tag":399,"props":1682,"children":1683},{},[1684,1686,1691,1693,1699],{"type":40,"value":1685},"Call ",{"type":35,"tag":43,"props":1687,"children":1689},{"className":1688},[],[1690],{"type":40,"value":1675},{"type":40,"value":1692}," with ",{"type":35,"tag":43,"props":1694,"children":1696},{"className":1695},[],[1697],{"type":40,"value":1698},"package_path",{"type":40,"value":1700}," set to the package directory.",{"type":35,"tag":399,"props":1702,"children":1703},{},[1704],{"type":40,"value":1705},"The tool sets error and returns detailed error messages if the package does not compile.",{"type":35,"tag":36,"props":1707,"children":1708},{},[1709],{"type":40,"value":1710},"Notice that like with a build system, the tool is idempotent, and does not cause recompilation\nif the compilation result and sources are up-to-date.",{"type":35,"tag":52,"props":1712,"children":1714},{"id":1713},"package-manifest",[1715],{"type":40,"value":1716},"Package Manifest",{"type":35,"tag":36,"props":1718,"children":1719},{},[1720,1721,1727],{"type":40,"value":1669},{"type":35,"tag":43,"props":1722,"children":1724},{"className":1723},[],[1725],{"type":40,"value":1726},"move_package_manifest",{"type":40,"value":1728}," MCP tool to discover source files and dependencies\nof a Move package:",{"type":35,"tag":395,"props":1730,"children":1731},{},[1732,1748],{"type":35,"tag":399,"props":1733,"children":1734},{},[1735,1736,1741,1742,1747],{"type":40,"value":1685},{"type":35,"tag":43,"props":1737,"children":1739},{"className":1738},[],[1740],{"type":40,"value":1726},{"type":40,"value":1692},{"type":35,"tag":43,"props":1743,"children":1745},{"className":1744},[],[1746],{"type":40,"value":1698},{"type":40,"value":1700},{"type":35,"tag":399,"props":1749,"children":1750},{},[1751,1753,1759,1761,1767],{"type":40,"value":1752},"The result includes ",{"type":35,"tag":43,"props":1754,"children":1756},{"className":1755},[],[1757],{"type":40,"value":1758},"source_paths",{"type":40,"value":1760}," (target modules) and ",{"type":35,"tag":43,"props":1762,"children":1764},{"className":1763},[],[1765],{"type":40,"value":1766},"dep_paths",{"type":40,"value":1768}," (dependencies).",{"type":35,"tag":52,"props":1770,"children":1772},{"id":1771},"querying-package-structure",[1773],{"type":40,"value":1774},"Querying Package Structure",{"type":35,"tag":36,"props":1776,"children":1777},{},[1778,1779,1785],{"type":40,"value":1669},{"type":35,"tag":43,"props":1780,"children":1782},{"className":1781},[],[1783],{"type":40,"value":1784},"move_package_query",{"type":40,"value":1786}," MCP tool to inspect the structure of a Move package.",{"type":35,"tag":36,"props":1788,"children":1789},{},[1790],{"type":40,"value":1791},"Parameters:",{"type":35,"tag":395,"props":1793,"children":1794},{},[1795,1808,1822],{"type":35,"tag":399,"props":1796,"children":1797},{},[1798,1806],{"type":35,"tag":62,"props":1799,"children":1800},{},[1801],{"type":35,"tag":43,"props":1802,"children":1804},{"className":1803},[],[1805],{"type":40,"value":1698},{"type":40,"value":1807}," (required) — path to the Move package directory.",{"type":35,"tag":399,"props":1809,"children":1810},{},[1811,1820],{"type":35,"tag":62,"props":1812,"children":1813},{},[1814],{"type":35,"tag":43,"props":1815,"children":1817},{"className":1816},[],[1818],{"type":40,"value":1819},"query",{"type":40,"value":1821}," (required) — one of the query types below.",{"type":35,"tag":399,"props":1823,"children":1824},{},[1825,1834,1836,1842,1844,1850],{"type":35,"tag":62,"props":1826,"children":1827},{},[1828],{"type":35,"tag":43,"props":1829,"children":1831},{"className":1830},[],[1832],{"type":40,"value":1833},"function",{"type":40,"value":1835}," (required for ",{"type":35,"tag":43,"props":1837,"children":1839},{"className":1838},[],[1840],{"type":40,"value":1841},"function_usage",{"type":40,"value":1843},") — function name in the form ",{"type":35,"tag":43,"props":1845,"children":1847},{"className":1846},[],[1848],{"type":40,"value":1849},"module_name::function_name",{"type":40,"value":487},{"type":35,"tag":351,"props":1852,"children":1854},{"id":1853},"query-types",[1855],{"type":40,"value":1856},"Query Types",{"type":35,"tag":395,"props":1858,"children":1859},{},[1860,1874,1888,1902],{"type":35,"tag":399,"props":1861,"children":1862},{},[1863,1872],{"type":35,"tag":62,"props":1864,"children":1865},{},[1866],{"type":35,"tag":43,"props":1867,"children":1869},{"className":1868},[],[1870],{"type":40,"value":1871},"dep_graph",{"type":40,"value":1873}," — returns a map from each module to the modules it depends on.\nUseful for understanding module layering and import structure.",{"type":35,"tag":399,"props":1875,"children":1876},{},[1877,1886],{"type":35,"tag":62,"props":1878,"children":1879},{},[1880],{"type":35,"tag":43,"props":1881,"children":1883},{"className":1882},[],[1884],{"type":40,"value":1885},"module_summary",{"type":40,"value":1887}," — returns a summary of each module's constants, structs,\nand functions. Useful for getting an overview without reading all source files.",{"type":35,"tag":399,"props":1889,"children":1890},{},[1891,1900],{"type":35,"tag":62,"props":1892,"children":1893},{},[1894],{"type":35,"tag":43,"props":1895,"children":1897},{"className":1896},[],[1898],{"type":40,"value":1899},"call_graph",{"type":40,"value":1901}," — returns a function-level call graph as a map from each\nfunction to the functions it calls.",{"type":35,"tag":399,"props":1903,"children":1904},{},[1905,1913,1915,1920],{"type":35,"tag":62,"props":1906,"children":1907},{},[1908],{"type":35,"tag":43,"props":1909,"children":1911},{"className":1910},[],[1912],{"type":40,"value":1841},{"type":40,"value":1914}," — returns direct and transitive calls\u002Fuses for a given\nfunction. \"called\" = direct calls; \"used\" = direct calls + closure captures.\nRequires the ",{"type":35,"tag":43,"props":1916,"children":1918},{"className":1917},[],[1919],{"type":40,"value":1833},{"type":40,"value":1921}," parameter.",{"type":35,"tag":52,"props":1923,"children":1925},{"id":1924},"spec-inference-reference",[1926],{"type":40,"value":1927},"Spec Inference Reference",{"type":35,"tag":351,"props":1929,"children":1931},{"id":1930},"wp-tool",[1932],{"type":40,"value":1933},"WP Tool",{"type":35,"tag":36,"props":1935,"children":1936},{},[1937,1939,1945],{"type":40,"value":1938},"Use ",{"type":35,"tag":43,"props":1940,"children":1942},{"className":1941},[],[1943],{"type":40,"value":1944},"move_package_wp",{"type":40,"value":1946},", a weakest precondition (WP)\ninference tool for deriving specs. Do not run this tool outside of this workflow.",{"type":35,"tag":36,"props":1948,"children":1949},{},[1950],{"type":40,"value":1791},{"type":35,"tag":395,"props":1952,"children":1953},{},[1954,1966,1993],{"type":35,"tag":399,"props":1955,"children":1956},{},[1957,1965],{"type":35,"tag":62,"props":1958,"children":1959},{},[1960],{"type":35,"tag":43,"props":1961,"children":1963},{"className":1962},[],[1964],{"type":40,"value":1698},{"type":40,"value":1807},{"type":35,"tag":399,"props":1967,"children":1968},{},[1969,1977,1979,1985,1986,1991],{"type":35,"tag":62,"props":1970,"children":1971},{},[1972],{"type":35,"tag":43,"props":1973,"children":1975},{"className":1974},[],[1976],{"type":40,"value":100},{"type":40,"value":1978}," (optional) — ",{"type":35,"tag":43,"props":1980,"children":1982},{"className":1981},[],[1983],{"type":40,"value":1984},"module_name",{"type":40,"value":76},{"type":35,"tag":43,"props":1987,"children":1989},{"className":1988},[],[1990],{"type":40,"value":1849},{"type":40,"value":1992},".\nWhen omitted, all target modules are inferred.",{"type":35,"tag":399,"props":1994,"children":1995},{},[1996,2005,2007,2013,2015,2020,2022,2028,2030,2035],{"type":35,"tag":62,"props":1997,"children":1998},{},[1999],{"type":35,"tag":43,"props":2000,"children":2002},{"className":2001},[],[2003],{"type":40,"value":2004},"spec_output",{"type":40,"value":2006}," (optional, default ",{"type":35,"tag":43,"props":2008,"children":2010},{"className":2009},[],[2011],{"type":40,"value":2012},"\"inline\"",{"type":40,"value":2014},") — where to write inferred specs.\n",{"type":35,"tag":43,"props":2016,"children":2018},{"className":2017},[],[2019],{"type":40,"value":2012},{"type":40,"value":2021}," injects specs into the original source files.\n",{"type":35,"tag":43,"props":2023,"children":2025},{"className":2024},[],[2026],{"type":40,"value":2027},"\"file\"",{"type":40,"value":2029}," writes separate ",{"type":35,"tag":43,"props":2031,"children":2033},{"className":2032},[],[2034],{"type":40,"value":124},{"type":40,"value":2036}," files alongside the sources, leaving\noriginals untouched.",{"type":35,"tag":36,"props":2038,"children":2039},{},[2040,2045,2047,2052,2054,2059,2061,2066],{"type":35,"tag":62,"props":2041,"children":2042},{},[2043],{"type":40,"value":2044},"Important:",{"type":40,"value":2046}," If the user asks for specs in a separate file, in a spec file, or\nto keep the source untouched, you ",{"type":35,"tag":62,"props":2048,"children":2049},{},[2050],{"type":40,"value":2051},"must",{"type":40,"value":2053}," pass ",{"type":35,"tag":43,"props":2055,"children":2057},{"className":2056},[],[2058],{"type":40,"value":116},{"type":40,"value":2060},". Only use\nthe default ",{"type":35,"tag":43,"props":2062,"children":2064},{"className":2063},[],[2065],{"type":40,"value":2012},{"type":40,"value":2067}," when the user wants specs added directly into their source.",{"type":35,"tag":36,"props":2069,"children":2070},{},[2071,2073,2078],{"type":40,"value":2072},"If the program contains loops, they are broken into exit and iteration points.\nLoop variables are havoced and the loop invariant is expected to fix them.\nWithout loop invariants, derived WPs leave values in arbitrary state, resulting\nin ",{"type":35,"tag":43,"props":2074,"children":2076},{"className":2075},[],[2077],{"type":40,"value":1625},{"type":40,"value":2079}," properties. You must add loop invariants to fix this.",{"type":35,"tag":36,"props":2081,"children":2082},{},[2083,2088,2090,2095,2097,2102,2104,2109],{"type":35,"tag":62,"props":2084,"children":2085},{},[2086],{"type":40,"value":2087},"Before every WP re-run:",{"type":40,"value":2089}," remove all existing ",{"type":35,"tag":43,"props":2091,"children":2093},{"className":2092},[],[2094],{"type":40,"value":108},{"type":40,"value":2096},",\n",{"type":35,"tag":43,"props":2098,"children":2100},{"className":2099},[],[2101],{"type":40,"value":1625},{"type":40,"value":2103},", and ",{"type":35,"tag":43,"props":2105,"children":2107},{"className":2106},[],[2108],{"type":40,"value":1636},{"type":40,"value":2110},"\nconditions from spec blocks in scope. The WP tool will regenerate them; keeping\nstale copies leads to duplicate conditions.",{"type":35,"tag":351,"props":2112,"children":2114},{"id":2113},"common-pitfalls-in-ai-generated-spec-expressions",[2115],{"type":40,"value":2116},"Common Pitfalls in AI Generated Spec Expressions",{"type":35,"tag":36,"props":2118,"children":2119},{},[2120,2122,2127],{"type":40,"value":2121},"Respect the ",{"type":35,"tag":43,"props":2123,"children":2125},{"className":2124},[],[2126],{"type":40,"value":448},{"type":40,"value":2128}," usage rules and expression restrictions from the spec\nlanguage reference above — violating them causes compilation errors. Additionally:",{"type":35,"tag":395,"props":2130,"children":2131},{},[2132],{"type":35,"tag":399,"props":2133,"children":2134},{},[2135,2140,2142,2148,2150,2156],{"type":35,"tag":62,"props":2136,"children":2137},{},[2138],{"type":40,"value":2139},"Do not forget space after property.",{"type":40,"value":2141}," Write ",{"type":35,"tag":43,"props":2143,"children":2145},{"className":2144},[],[2146],{"type":40,"value":2147},"aborts_if [inferred] !exists p",{"type":40,"value":2149},"\nwith spaces separating the ",{"type":35,"tag":43,"props":2151,"children":2153},{"className":2152},[],[2154],{"type":40,"value":2155},"[..]",{"type":40,"value":2157}," property.",{"type":35,"tag":351,"props":2159,"children":2161},{"id":2160},"avoiding-duplicate-conditions",[2162],{"type":40,"value":2163},"Avoiding Duplicate Conditions",{"type":35,"tag":36,"props":2165,"children":2166},{},[2167],{"type":40,"value":2168},"Before adding any condition (ensures, aborts_if, loop invariant, etc.), check\nwhether an equivalent condition already exists in the same spec block. Do not\nadd a condition that is semantically identical to one already present — even if\nthe WP tool produced it again.",{"type":35,"tag":351,"props":2170,"children":2172},{"id":2171},"respecting-filter-scope",[2173],{"type":40,"value":2174},"Respecting Filter Scope",{"type":35,"tag":36,"props":2176,"children":2177},{},[2178,2180,2185],{"type":40,"value":2179},"When a ",{"type":35,"tag":43,"props":2181,"children":2183},{"className":2182},[],[2184],{"type":40,"value":100},{"type":40,"value":2186}," restricts inference to a specific function or module, only modify\nspec blocks for functions within that scope. Do not touch, add, or alter specs\nof any function outside the filter. Leave all other code and spec blocks exactly\nas they are.",{"type":35,"tag":351,"props":2188,"children":2190},{"id":2189},"marking-inferred-conditions",[2191],{"type":40,"value":2192},"Marking Inferred Conditions",{"type":35,"tag":36,"props":2194,"children":2195},{},[2196,2198,2203,2205,2210],{"type":40,"value":2197},"Every condition you write during inference — whether during loop invariant\nsynthesis or simplification — must carry the ",{"type":35,"tag":43,"props":2199,"children":2201},{"className":2200},[],[2202],{"type":40,"value":108},{"type":40,"value":2204}," property.\nConditions without\n",{"type":35,"tag":43,"props":2206,"children":2208},{"className":2207},[],[2209],{"type":40,"value":108},{"type":40,"value":2211}," are treated as user-written and will not be cleaned up on re-runs.",{"type":35,"tag":549,"props":2213,"children":2217},{"className":2214,"code":2216,"language":40},[2215],"language-text","ensures [inferred] result == x + 1;\naborts_if [inferred] x + y > MAX_U64;\ninvariant [inferred] acc == sum_up_to(i);\n",[2218],{"type":35,"tag":43,"props":2219,"children":2220},{"__ignoreMap":554},[2221],{"type":40,"value":2216},{"type":35,"tag":36,"props":2223,"children":2224},{},[2225,2227,2232,2233,2238,2240,2246],{"type":40,"value":2226},"Never write a bare ",{"type":35,"tag":43,"props":2228,"children":2230},{"className":2229},[],[2231],{"type":40,"value":167},{"type":40,"value":808},{"type":35,"tag":43,"props":2234,"children":2236},{"className":2235},[],[2237],{"type":40,"value":175},{"type":40,"value":2239},", or ",{"type":35,"tag":43,"props":2241,"children":2243},{"className":2242},[],[2244],{"type":40,"value":2245},"invariant",{"type":40,"value":2247}," during inference.",{"type":35,"tag":351,"props":2249,"children":2251},{"id":2250},"synthesizing-loop-invariants",[2252],{"type":40,"value":2253},"Synthesizing Loop Invariants",{"type":35,"tag":36,"props":2255,"children":2256},{},[2257,2259,2264,2265,2271],{"type":40,"value":2258},"Add loop invariants for every loop in the target code which doesn't yet have one.\nRemove all existing ",{"type":35,"tag":43,"props":2260,"children":2262},{"className":2261},[],[2263],{"type":40,"value":108},{"type":40,"value":861},{"type":35,"tag":43,"props":2266,"children":2268},{"className":2267},[],[2269],{"type":40,"value":2270},"[inferred = *]",{"type":40,"value":2272},"\nconditions.",{"type":35,"tag":36,"props":2274,"children":2275},{},[2276,2286,2288,2293,2295,2301,2303,2308],{"type":35,"tag":62,"props":2277,"children":2278},{},[2279,2284],{"type":35,"tag":43,"props":2280,"children":2282},{"className":2281},[],[2283],{"type":40,"value":448},{"type":40,"value":2285}," in loop invariants:",{"type":40,"value":2287}," ",{"type":35,"tag":43,"props":2289,"children":2291},{"className":2290},[],[2292],{"type":40,"value":625},{"type":40,"value":2294}," is only allowed when ",{"type":35,"tag":43,"props":2296,"children":2298},{"className":2297},[],[2299],{"type":40,"value":2300},"x",{"type":40,"value":2302}," is a simple\nfunction parameter name. To refer to a value from before the loop, save it into\na ",{"type":35,"tag":43,"props":2304,"children":2306},{"className":2305},[],[2307],{"type":40,"value":1264},{"type":40,"value":2309}," binding before the loop and reference that local in the invariant.",{"type":35,"tag":36,"props":2311,"children":2312},{},[2313,2315,2320,2322,2328],{"type":40,"value":2314},"Loop invariants often need ",{"type":35,"tag":62,"props":2316,"children":2317},{},[2318],{"type":40,"value":2319},"recursive spec helper functions",{"type":40,"value":2321}," to express\nproperties about values built up across iterations (e.g. partial sums,\naccumulated vectors, running products). When no existing spec function captures\nthe relationship, define a new ",{"type":35,"tag":43,"props":2323,"children":2325},{"className":2324},[],[2326],{"type":40,"value":2327},"spec fun",{"type":40,"value":2329}," in the same module. Typical pattern:",{"type":35,"tag":549,"props":2331,"children":2334},{"className":2332,"code":2333,"language":40},[2215],"spec fun sum_up_to(n: u64): u64 {\n    if (n == 0) { 0 } else { n + sum_up_to(n - 1) }\n}\n",[2335],{"type":35,"tag":43,"props":2336,"children":2337},{"__ignoreMap":554},[2338],{"type":40,"value":2333},{"type":35,"tag":36,"props":2340,"children":2341},{},[2342],{"type":40,"value":2343},"Then reference the helper in the loop invariant:",{"type":35,"tag":549,"props":2345,"children":2348},{"className":2346,"code":2347,"language":40},[2215],"invariant [inferred] acc == sum_up_to(i);\n",[2349],{"type":35,"tag":43,"props":2350,"children":2351},{"__ignoreMap":554},[2352],{"type":40,"value":2347},{"type":35,"tag":36,"props":2354,"children":2355},{},[2356,2358,2364],{"type":40,"value":2357},"Create as many helpers as needed to make invariants precise and verifiable.\nAdd a ",{"type":35,"tag":43,"props":2359,"children":2361},{"className":2360},[],[2362],{"type":40,"value":2363},"\u002F\u002F\u002F",{"type":40,"value":2365}," doc comment to every new spec helper explaining the property it\ncaptures. Place new spec helper functions below the Move function and spec\nblock that introduce them. Place lemmas for a helper directly beneath that\nhelper's declaration.",{"type":35,"tag":351,"props":2367,"children":2369},{"id":2368},"data-invariants-and-global-update-invariants",[2370],{"type":40,"value":2371},"Data Invariants and Global Update Invariants",{"type":35,"tag":36,"props":2373,"children":2374},{},[2375,2377,2383],{"type":40,"value":2376},"Data invariants (",{"type":35,"tag":43,"props":2378,"children":2380},{"className":2379},[],[2381],{"type":40,"value":2382},"spec Struct { invariant \u003Cexpr>; }",{"type":40,"value":2384},") express properties that\nmust hold for every instance of a struct at all times. The prover checks them on\nconstruction and after every mutation.",{"type":35,"tag":36,"props":2386,"children":2387},{},[2388],{"type":40,"value":2389},"Good candidates for data invariants:",{"type":35,"tag":395,"props":2391,"children":2392},{},[2393,2406],{"type":35,"tag":399,"props":2394,"children":2395},{},[2396,2398,2404],{"type":40,"value":2397},"Positivity \u002F non-zero bounds on fields that are denominators or reserves\n(e.g., ",{"type":35,"tag":43,"props":2399,"children":2401},{"className":2400},[],[2402],{"type":40,"value":2403},"invariant balance > 0;",{"type":40,"value":2405},"). These eliminate impossible states and help the\nprover rule out division-by-zero or underflow in callers.",{"type":35,"tag":399,"props":2407,"children":2408},{},[2409,2411,2417],{"type":40,"value":2410},"Relationships between fields that hold by construction and are preserved by\nall operations (e.g., ",{"type":35,"tag":43,"props":2412,"children":2414},{"className":2413},[],[2415],{"type":40,"value":2416},"invariant len == vector::length(data);",{"type":40,"value":694},{"type":35,"tag":36,"props":2419,"children":2420},{},[2421,2423,2429],{"type":40,"value":2422},"Do NOT add data invariants that are broken by normal operations. For example,\nan AMM pool's exchange rate changes after every swap — a fixed-ratio invariant\nlike ",{"type":35,"tag":43,"props":2424,"children":2426},{"className":2425},[],[2427],{"type":40,"value":2428},"invariant x == y;",{"type":40,"value":2430}," will fail verification on swap.",{"type":35,"tag":36,"props":2432,"children":2433},{},[2434,2436,2442],{"type":40,"value":2435},"Global update invariants (",{"type":35,"tag":43,"props":2437,"children":2439},{"className":2438},[],[2440],{"type":40,"value":2441},"spec module { invariant update ...; }",{"type":40,"value":2443},") constrain\nhow a resource changes between its old and new state during any modification.\nThey are verified once per function that modifies the resource, then assumed at\nevery call site — including inside loops. This makes them powerful for loop\nverification: the prover gets the property at each iteration for free without\nneeding recursive spec helpers.",{"type":35,"tag":549,"props":2445,"children":2448},{"className":2446,"code":2447,"language":40},[2215],"spec module {\n    invariant update forall addr: address\n        where old(exists\u003CT>(addr)) && exists\u003CT>(addr):\n        old(global\u003CT>(addr)).field \u003C= global\u003CT>(addr).field;\n}\n",[2449],{"type":35,"tag":43,"props":2450,"children":2451},{"__ignoreMap":554},[2452],{"type":40,"value":2447},{"type":35,"tag":36,"props":2454,"children":2455},{},[2456],{"type":40,"value":2457},"Good candidates for update invariants:",{"type":35,"tag":395,"props":2459,"children":2460},{},[2461,2466,2479],{"type":35,"tag":399,"props":2462,"children":2463},{},[2464],{"type":40,"value":2465},"Monotonicity properties: a value that only grows or only shrinks\n(e.g., total supply, sequence numbers, timestamps).",{"type":35,"tag":399,"props":2467,"children":2468},{},[2469,2471,2477],{"type":40,"value":2470},"Conservation laws: a quantity preserved across state transitions\n(e.g., ",{"type":35,"tag":43,"props":2472,"children":2474},{"className":2473},[],[2475],{"type":40,"value":2476},"old(x) + old(y) == x + y",{"type":40,"value":2478}," for token transfers).",{"type":35,"tag":399,"props":2480,"children":2481},{},[2482,2484,2490],{"type":40,"value":2483},"Product bounds: for AMM-style contracts, the constant-product property\n",{"type":35,"tag":43,"props":2485,"children":2487},{"className":2486},[],[2488],{"type":40,"value":2489},"old(rx) * old(ry) \u003C= rx * ry",{"type":40,"value":2491}," (non-decreasing due to integer division\nrounding). This is verified once on the swap function, then the prover uses\nit at every loop iteration to bound intermediate reserve values without\nrecursive spec helpers.",{"type":35,"tag":36,"props":2493,"children":2494},{},[2495],{"type":40,"value":2496},"Update invariants are especially valuable when loop bodies call opaque functions.\nThe prover cannot inline the function body but CAN use the update invariant to\nconstrain how the resource changed — bridging the gap between opaque call\nsemantics and loop invariant preservation.",{"type":35,"tag":36,"props":2498,"children":2499},{},[2500,2505,2507,2513,2515,2521],{"type":35,"tag":62,"props":2501,"children":2502},{},[2503],{"type":40,"value":2504},"Combining data and update invariants with loops:",{"type":40,"value":2506}," A data invariant like\n",{"type":35,"tag":43,"props":2508,"children":2510},{"className":2509},[],[2511],{"type":40,"value":2512},"x > 0 && y > 0",{"type":40,"value":2514}," plus an update invariant like ",{"type":35,"tag":43,"props":2516,"children":2518},{"className":2517},[],[2519],{"type":40,"value":2520},"old(x) * old(y) \u003C= x * y",{"type":40,"value":2522},"\ngives the prover both a floor on individual fields and a relationship between\nthem at every loop step — without any recursive spec functions or manual\nunfolding. This pattern is the key to verifying iterative operations over\nstateful resources.",{"type":35,"tag":52,"props":2524,"children":2526},{"id":2525},"writing-and-editing-specs",[2527],{"type":40,"value":2528},"Writing and Editing Specs",{"type":35,"tag":36,"props":2530,"children":2531},{},[2532],{"type":40,"value":2533},"When writing or editing specifications:",{"type":35,"tag":661,"props":2535,"children":2536},{},[2537,2548,2553,2565,2577,2589],{"type":35,"tag":399,"props":2538,"children":2539},{},[2540,2541,2546],{"type":40,"value":1938},{"type":35,"tag":43,"props":2542,"children":2544},{"className":2543},[],[2545],{"type":40,"value":1726},{"type":40,"value":2547}," to discover source files.",{"type":35,"tag":399,"props":2549,"children":2550},{},[2551],{"type":40,"value":2552},"Read the function body to understand its behavior and abort conditions.",{"type":35,"tag":399,"props":2554,"children":2555},{},[2556,2558,2563],{"type":40,"value":2557},"Write ",{"type":35,"tag":43,"props":2559,"children":2561},{"className":2560},[],[2562],{"type":40,"value":367},{"type":40,"value":2564}," blocks after each function, following the Move Specification\nLanguage rules above.",{"type":35,"tag":399,"props":2566,"children":2567},{},[2568,2569,2575],{"type":40,"value":2557},{"type":35,"tag":43,"props":2570,"children":2572},{"className":2571},[],[2573],{"type":40,"value":2574},"spec lemma lemma_name ...",{"type":40,"value":2576}," block after the function for which they are introduced.",{"type":35,"tag":399,"props":2578,"children":2579},{},[2580,2582,2587],{"type":40,"value":2581},"Spec functions are put into a ",{"type":35,"tag":43,"props":2583,"children":2585},{"className":2584},[],[2586],{"type":40,"value":2327},{"type":40,"value":2588}," declarations.",{"type":35,"tag":399,"props":2590,"children":2591},{},[2592,2594,2599],{"type":40,"value":2593},"If the project already uses ",{"type":35,"tag":43,"props":2595,"children":2597},{"className":2596},[],[2598],{"type":40,"value":124},{"type":40,"value":2600}," files, put new specs into that file instead of the\nmain Move file.",{"type":35,"tag":36,"props":2602,"children":2603},{},[2604,2614,2616,2621,2623,2628,2630,2636,2638,2643,2645,2651,2653,2659,2661,2667],{"type":35,"tag":62,"props":2605,"children":2606},{},[2607,2612],{"type":35,"tag":43,"props":2608,"children":2610},{"className":2609},[],[2611],{"type":40,"value":124},{"type":40,"value":2613}," files:",{"type":40,"value":2615}," A ",{"type":35,"tag":43,"props":2617,"children":2619},{"className":2618},[],[2620],{"type":40,"value":124},{"type":40,"value":2622}," file is compiled as part of the same module\nas the corresponding source file. Use ",{"type":35,"tag":43,"props":2624,"children":2626},{"className":2625},[],[2627],{"type":40,"value":132},{"type":40,"value":2629}," (the keyword ",{"type":35,"tag":43,"props":2631,"children":2633},{"className":2632},[],[2634],{"type":40,"value":2635},"module",{"type":40,"value":2637},",\nnot a module name) to declare module-level spec items (helper functions, lemmas).\nUse ",{"type":35,"tag":43,"props":2639,"children":2641},{"className":2640},[],[2642],{"type":40,"value":210},{"type":40,"value":2644}," to add conditions to functions defined in the main source.\nThere is no ",{"type":35,"tag":43,"props":2646,"children":2648},{"className":2647},[],[2649],{"type":40,"value":2650},"spec \u003Cmodule_name> { }",{"type":40,"value":2652}," syntax — ",{"type":35,"tag":43,"props":2654,"children":2656},{"className":2655},[],[2657],{"type":40,"value":2658},"spec name { }",{"type":40,"value":2660}," always targets a\nfunction named ",{"type":35,"tag":43,"props":2662,"children":2664},{"className":2663},[],[2665],{"type":40,"value":2666},"name",{"type":40,"value":487},{"type":35,"tag":351,"props":2669,"children":2671},{"id":2670},"simplifying-specifications",[2672],{"type":40,"value":2673},"Simplifying Specifications",{"type":35,"tag":36,"props":2675,"children":2676},{},[2677],{"type":40,"value":2678},"Work through the following in order when cleaning up inferred or hand-written specs.",{"type":35,"tag":36,"props":2680,"children":2681},{},[2682,2687,2689,2694,2696,2702],{"type":35,"tag":62,"props":2683,"children":2684},{},[2685],{"type":40,"value":2686},"Remove vacuous conditions.",{"type":40,"value":2688}," Delete every condition marked ",{"type":35,"tag":43,"props":2690,"children":2692},{"className":2691},[],[2693],{"type":40,"value":1625},{"type":40,"value":2695},".\nThese arise from havoced loop variables without sufficient invariants and are\nsemantically meaningless (e.g.\n",{"type":35,"tag":43,"props":2697,"children":2699},{"className":2698},[],[2700],{"type":40,"value":2701},"ensures [inferred = vacuous] forall x: u64: result == x",{"type":40,"value":694},{"type":35,"tag":36,"props":2704,"children":2705},{},[2706,2711,2713,2719,2720,2726,2727,2733,2735,2740,2742,2747],{"type":35,"tag":62,"props":2707,"children":2708},{},[2709],{"type":40,"value":2710},"Eliminate quantifiers.",{"type":40,"value":2712}," Conditions with quantifiers over unbounded types\n(",{"type":35,"tag":43,"props":2714,"children":2716},{"className":2715},[],[2717],{"type":40,"value":2718},"forall x: u64",{"type":40,"value":808},{"type":35,"tag":43,"props":2721,"children":2723},{"className":2722},[],[2724],{"type":40,"value":2725},"exists x: u64",{"type":40,"value":808},{"type":35,"tag":43,"props":2728,"children":2730},{"className":2729},[],[2731],{"type":40,"value":2732},"forall x: address",{"type":40,"value":2734},") cause SMT solver timeouts.\nThey are often marked ",{"type":35,"tag":43,"props":2736,"children":2738},{"className":2737},[],[2739],{"type":40,"value":1636},{"type":40,"value":2741}," but not always. Replace each with an\nequivalent ",{"type":35,"tag":62,"props":2743,"children":2744},{},[2745],{"type":40,"value":2746},"non-quantified",{"type":40,"value":2748}," expression:",{"type":35,"tag":395,"props":2750,"children":2751},{},[2752,2763],{"type":35,"tag":399,"props":2753,"children":2754},{},[2755,2761],{"type":35,"tag":43,"props":2756,"children":2758},{"className":2757},[],[2759],{"type":40,"value":2760},"exists x: u64: x \u003C n && f(x)",{"type":40,"value":2762}," — replace with a concrete bound or closed-form\nexpression derived from the loop logic.",{"type":35,"tag":399,"props":2764,"children":2765},{},[2766,2772,2774,2780],{"type":35,"tag":43,"props":2767,"children":2769},{"className":2768},[],[2770],{"type":40,"value":2771},"forall x: address: x != a ==> g(x)",{"type":40,"value":2773}," — this expresses a frame condition (\"nothing\nelse changed\"). Replace with an explicit ",{"type":35,"tag":43,"props":2775,"children":2777},{"className":2776},[],[2778],{"type":40,"value":2779},"modifies",{"type":40,"value":2781}," clause or enumerate the affected\naddresses.",{"type":35,"tag":36,"props":2783,"children":2784},{},[2785,2790,2792,2798],{"type":35,"tag":62,"props":2786,"children":2787},{},[2788],{"type":40,"value":2789},"Ensure quantifiers have triggers.",{"type":40,"value":2791}," Quantifiers without triggers must be avoided. Move\nsupports lists of triggers as in ",{"type":35,"tag":43,"props":2793,"children":2795},{"className":2794},[],[2796],{"type":40,"value":2797},"Q x: T, y: R {p1, .., pn}..{q1, .., qn}: e",{"type":40,"value":2799},", where each outer\nlist is an alternative where all inner patterns must match. Notice that only triggers over\nuninterpreted functions are allowed, not over builtin operators.",{"type":35,"tag":36,"props":2801,"children":2802},{},[2803,2816,2818,2824],{"type":35,"tag":62,"props":2804,"children":2805},{},[2806,2808,2814],{"type":40,"value":2807},"Simplify ",{"type":35,"tag":43,"props":2809,"children":2811},{"className":2810},[],[2812],{"type":40,"value":2813},"update_field",{"type":40,"value":2815}," expressions.",{"type":40,"value":2817}," The WP engine uses\n",{"type":35,"tag":43,"props":2819,"children":2821},{"className":2820},[],[2822],{"type":40,"value":2823},"update_field(s, field, val)",{"type":40,"value":2825}," for struct mutations. Rewrite to direct struct\nconstruction when all fields are determined, e.g.:",{"type":35,"tag":395,"props":2827,"children":2828},{},[2829,2855],{"type":35,"tag":399,"props":2830,"children":2831},{},[2832,2838,2840,2846,2848,2854],{"type":35,"tag":43,"props":2833,"children":2835},{"className":2834},[],[2836],{"type":40,"value":2837},"update_field(old(global\u003CT>(addr)), value, v)",{"type":40,"value":2839}," becomes\n",{"type":35,"tag":43,"props":2841,"children":2843},{"className":2842},[],[2844],{"type":40,"value":2845},"T { value: v, ..old(global\u003CT>(addr)) }",{"type":40,"value":2847},", or when the struct has a single field,\nsimply ",{"type":35,"tag":43,"props":2849,"children":2851},{"className":2850},[],[2852],{"type":40,"value":2853},"T { value: v }",{"type":40,"value":487},{"type":35,"tag":399,"props":2856,"children":2857},{},[2858,2860,2866,2867,2873],{"type":40,"value":2859},"Nested ",{"type":35,"tag":43,"props":2861,"children":2863},{"className":2862},[],[2864],{"type":40,"value":2865},"update_field(update_field(old(p), x, a), y, b)",{"type":40,"value":2839},{"type":35,"tag":43,"props":2868,"children":2870},{"className":2869},[],[2871],{"type":40,"value":2872},"Point { x: a, y: b }",{"type":40,"value":2874}," when all fields are covered.",{"type":35,"tag":36,"props":2876,"children":2877},{},[2878,2883,2885,2891,2893,2899,2900,2906,2908,2914,2916,2921],{"type":35,"tag":62,"props":2879,"children":2880},{},[2881],{"type":40,"value":2882},"Consolidate unrolled specs.",{"type":40,"value":2884}," When ",{"type":35,"tag":43,"props":2886,"children":2888},{"className":2887},[],[2889],{"type":40,"value":2890},"pragma unroll",{"type":40,"value":2892}," is used, the WP produces one\ncondition per unrolling step (e.g. ",{"type":35,"tag":43,"props":2894,"children":2896},{"className":2895},[],[2897],{"type":40,"value":2898},"n == 0 ==> ...",{"type":40,"value":808},{"type":35,"tag":43,"props":2901,"children":2903},{"className":2902},[],[2904],{"type":40,"value":2905},"n == 1 ==> ...",{"type":40,"value":2907},", ...,\n",{"type":35,"tag":43,"props":2909,"children":2911},{"className":2910},[],[2912],{"type":40,"value":2913},"k \u003C n ==> ...",{"type":40,"value":2915},"). If there is a closed-form generalization, replace the case list\nwith a single condition. Remove the ",{"type":35,"tag":43,"props":2917,"children":2919},{"className":2918},[],[2920],{"type":40,"value":2890},{"type":40,"value":2922}," once the closed-form is in place.",{"type":35,"tag":36,"props":2924,"children":2925},{},[2926],{"type":35,"tag":62,"props":2927,"children":2928},{},[2929],{"type":40,"value":2930},"General cleanup:",{"type":35,"tag":395,"props":2932,"children":2933},{},[2934,2973,2985,3057,3094],{"type":35,"tag":399,"props":2935,"children":2936},{},[2937,2939,2944,2946,2951,2953,2958,2959,2964,2966,2971],{"type":40,"value":2938},"Fix ",{"type":35,"tag":43,"props":2940,"children":2942},{"className":2941},[],[2943],{"type":40,"value":448},{"type":40,"value":2945}," usage: ",{"type":35,"tag":43,"props":2947,"children":2949},{"className":2948},[],[2950],{"type":40,"value":448},{"type":40,"value":2952}," in ",{"type":35,"tag":43,"props":2954,"children":2956},{"className":2955},[],[2957],{"type":40,"value":175},{"type":40,"value":76},{"type":35,"tag":43,"props":2960,"children":2962},{"className":2961},[],[2963],{"type":40,"value":1152},{"type":40,"value":2965}," is invalid — those\nclauses are already evaluated in the pre-state. Remove ",{"type":35,"tag":43,"props":2967,"children":2969},{"className":2968},[],[2970],{"type":40,"value":448},{"type":40,"value":2972}," wrappers.",{"type":35,"tag":399,"props":2974,"children":2975},{},[2976,2978,2983],{"type":40,"value":2977},"Remove redundant conditions implied by others or by language guarantees (e.g. an\n",{"type":35,"tag":43,"props":2979,"children":2981},{"className":2980},[],[2982],{"type":40,"value":175},{"type":40,"value":2984}," subsumed by a stronger one).",{"type":35,"tag":399,"props":2986,"children":2987},{},[2988,2990],{"type":40,"value":2989},"Simplify arithmetic. The WP engine mirrors the computation steps, producing\nexpressions that can be algebraically reduced:\n",{"type":35,"tag":395,"props":2991,"children":2992},{},[2993,3013,3033,3052],{"type":35,"tag":399,"props":2994,"children":2995},{},[2996,2998,3004,3006,3012],{"type":40,"value":2997},"Combine terms: ",{"type":35,"tag":43,"props":2999,"children":3001},{"className":3000},[],[3002],{"type":40,"value":3003},"(n - 1) * n \u002F 2 + n",{"type":40,"value":3005}," simplifies to ",{"type":35,"tag":43,"props":3007,"children":3009},{"className":3008},[],[3010],{"type":40,"value":3011},"n * (n + 1) \u002F 2",{"type":40,"value":487},{"type":35,"tag":399,"props":3014,"children":3015},{},[3016,3018,3024,3026,3032],{"type":40,"value":3017},"Flatten nested offsets: ",{"type":35,"tag":43,"props":3019,"children":3021},{"className":3020},[],[3022],{"type":40,"value":3023},"old(v) + 1 + 1",{"type":40,"value":3025}," becomes ",{"type":35,"tag":43,"props":3027,"children":3029},{"className":3028},[],[3030],{"type":40,"value":3031},"old(v) + 2",{"type":40,"value":487},{"type":35,"tag":399,"props":3034,"children":3035},{},[3036,3038,3044,3045,3051],{"type":40,"value":3037},"Simplify overflow bounds: ",{"type":35,"tag":43,"props":3039,"children":3041},{"className":3040},[],[3042],{"type":40,"value":3043},"v + (n - 1) > MAX_U64 - 1",{"type":40,"value":3025},{"type":35,"tag":43,"props":3046,"children":3048},{"className":3047},[],[3049],{"type":40,"value":3050},"v + n > MAX_U64",{"type":40,"value":487},{"type":35,"tag":399,"props":3053,"children":3054},{},[3055],{"type":40,"value":3056},"Specs use mathematical (unbounded) integers, so unlike Move code there is no\nrisk of underflow in spec expressions — reorder freely for clarity.",{"type":35,"tag":399,"props":3058,"children":3059},{},[3060,3072,3074,3079,3080,3085,3087,3092],{"type":35,"tag":62,"props":3061,"children":3062},{},[3063,3065,3070],{"type":40,"value":3064},"Keep ",{"type":35,"tag":43,"props":3066,"children":3068},{"className":3067},[],[3069],{"type":40,"value":108},{"type":40,"value":3071}," markers",{"type":40,"value":3073}," on all inferred conditions — they distinguish\ninferred specs from user-written ones and are needed for WP re-runs.\nRemove ",{"type":35,"tag":43,"props":3075,"children":3077},{"className":3076},[],[3078],{"type":40,"value":1625},{"type":40,"value":861},{"type":35,"tag":43,"props":3081,"children":3083},{"className":3082},[],[3084],{"type":40,"value":1636},{"type":40,"value":3086}," conditions entirely\n(as described above), but keep plain ",{"type":35,"tag":43,"props":3088,"children":3090},{"className":3089},[],[3091],{"type":40,"value":108},{"type":40,"value":3093}," on conditions you retain.",{"type":35,"tag":399,"props":3095,"children":3096},{},[3097,3107,3109,3115,3117,3122],{"type":35,"tag":62,"props":3098,"children":3099},{},[3100,3101],{"type":40,"value":3064},{"type":35,"tag":43,"props":3102,"children":3104},{"className":3103},[],[3105],{"type":40,"value":3106},"pragma opaque = true;",{"type":40,"value":3108}," — never remove it. It is essential for\nverification performance, not an inference artifact. If a function with\n",{"type":35,"tag":43,"props":3110,"children":3112},{"className":3111},[],[3113],{"type":40,"value":3114},"pragma opaque",{"type":40,"value":3116}," fails verification, add ",{"type":35,"tag":43,"props":3118,"children":3120},{"className":3119},[],[3121],{"type":40,"value":293},{"type":40,"value":3123}," rather\nthan removing the opaque pragma.",{"type":35,"tag":351,"props":3125,"children":3127},{"id":3126},"additional-rules-for-editing-specs",[3128],{"type":40,"value":3129},"Additional Rules for Editing Specs",{"type":35,"tag":661,"props":3131,"children":3132},{},[3133,3150,3160,3204,3234,3244],{"type":35,"tag":399,"props":3134,"children":3135},{},[3136,3141,3143,3148],{"type":35,"tag":62,"props":3137,"children":3138},{},[3139],{"type":40,"value":3140},"Do not change function bodies.",{"type":40,"value":3142}," Only modify ",{"type":35,"tag":43,"props":3144,"children":3146},{"className":3145},[],[3147],{"type":40,"value":347},{"type":40,"value":3149}," blocks and their contents.",{"type":35,"tag":399,"props":3151,"children":3152},{},[3153,3158],{"type":35,"tag":62,"props":3154,"children":3155},{},[3156],{"type":40,"value":3157},"Preserve",{"type":40,"value":3159}," any user-written (non-inferred) specifications exactly as they are.",{"type":35,"tag":399,"props":3161,"children":3162},{},[3163,3175,3177,3182,3184,3189,3190,3195,3197,3202],{"type":35,"tag":62,"props":3164,"children":3165},{},[3166,3168,3173],{"type":40,"value":3167},"Never drop ",{"type":35,"tag":43,"props":3169,"children":3171},{"className":3170},[],[3172],{"type":40,"value":175},{"type":40,"value":3174}," conditions.",{"type":40,"value":3176}," Every function that can abort must have\n",{"type":35,"tag":43,"props":3178,"children":3180},{"className":3179},[],[3181],{"type":40,"value":175},{"type":40,"value":3183}," conditions. The WP tool infers both ",{"type":35,"tag":43,"props":3185,"children":3187},{"className":3186},[],[3188],{"type":40,"value":167},{"type":40,"value":861},{"type":35,"tag":43,"props":3191,"children":3193},{"className":3192},[],[3194],{"type":40,"value":175},{"type":40,"value":3196}," —\nsimplify them but never remove them just because they are complex or hard to\nverify. If an ",{"type":35,"tag":43,"props":3198,"children":3200},{"className":3199},[],[3201],{"type":40,"value":175},{"type":40,"value":3203}," needs rewriting, replace it with a semantically\nequivalent expression, do not delete it.",{"type":35,"tag":399,"props":3205,"children":3206},{},[3207,3218,3220,3225,3227,3232],{"type":35,"tag":62,"props":3208,"children":3209},{},[3210,3212,3217],{"type":40,"value":3211},"Never remove ",{"type":35,"tag":43,"props":3213,"children":3215},{"className":3214},[],[3216],{"type":40,"value":3114},{"type":40,"value":487},{"type":40,"value":3219}," The WP tool marks inferred specs as opaque\nso the prover uses the spec contract instead of inlining the function body.\nRemoving it causes verification to re-analyze the implementation, leading to\ntimeouts. Preserve ",{"type":35,"tag":43,"props":3221,"children":3223},{"className":3222},[],[3224],{"type":40,"value":3106},{"type":40,"value":3226}," in every spec block that has it.\nIf verification fails on an opaque function (e.g., the prover cannot reason\nabout closure side effects), add ",{"type":35,"tag":43,"props":3228,"children":3230},{"className":3229},[],[3231],{"type":40,"value":293},{"type":40,"value":3233}," to disable\nverification while keeping the spec contract intact for callers.",{"type":35,"tag":399,"props":3235,"children":3236},{},[3237,3242],{"type":35,"tag":62,"props":3238,"children":3239},{},[3240],{"type":40,"value":3241},"Never duplicate conditions.",{"type":40,"value":3243}," Before adding any condition to a spec block,\ncheck whether an equivalent condition already exists. Do not create a condition\nthat is semantically identical to one already present in the same spec block.",{"type":35,"tag":399,"props":3245,"children":3246},{},[3247,3252,3254,3260],{"type":35,"tag":62,"props":3248,"children":3249},{},[3250],{"type":40,"value":3251},"No empty spec blocks.",{"type":40,"value":3253}," Never create or leave behind an empty\n",{"type":35,"tag":43,"props":3255,"children":3257},{"className":3256},[],[3258],{"type":40,"value":3259},"spec fun_name {}",{"type":40,"value":3261}," block. If removing inferred conditions would leave a spec\nblock with no conditions or pragmas, delete the entire block instead.",{"type":35,"tag":52,"props":3263,"children":3265},{"id":3264},"proofs-and-lemmas",[3266],{"type":40,"value":3267},"Proofs and Lemmas",{"type":35,"tag":351,"props":3269,"children":3271},{"id":3270},"example",[3272],{"type":40,"value":3273},"Example",{"type":35,"tag":549,"props":3275,"children":3277},{"className":551,"code":3276,"language":553,"meta":554,"style":554},"spec fun sum(n: u64): u64 {\n    if (n == 0) { 0 } else { n + sum(n - 1) }\n}\n\nspec lemma monotonicity(x: num, y: num) {\n    requires x \u003C= y;\n    ensures sum(x) \u003C= sum(y);\n} proof {\n    if (x \u003C y) {\n        assert sum(y - 1) \u003C= sum(y);\n        apply monotonicity(x, y - 1);\n    }\n}\n\n\nfun sum_up_to(n: u64): u64 { \u002F* iterative impl *\u002F }\nspec sum_up_to {\n    requires n \u003C= 5;\n    ensures result == sum(n);\n} proof {\n   forall x,y {sum(x), sum(y)} apply monotonicity(x, y);\n}\n",[3278],{"type":35,"tag":43,"props":3279,"children":3280},{"__ignoreMap":554},[3281,3289,3297,3304,3311,3319,3327,3335,3343,3351,3359,3367,3375,3382,3389,3396,3404,3412,3420,3428,3436,3445],{"type":35,"tag":560,"props":3282,"children":3283},{"class":562,"line":563},[3284],{"type":35,"tag":560,"props":3285,"children":3286},{},[3287],{"type":40,"value":3288},"spec fun sum(n: u64): u64 {\n",{"type":35,"tag":560,"props":3290,"children":3291},{"class":562,"line":572},[3292],{"type":35,"tag":560,"props":3293,"children":3294},{},[3295],{"type":40,"value":3296},"    if (n == 0) { 0 } else { n + sum(n - 1) }\n",{"type":35,"tag":560,"props":3298,"children":3299},{"class":562,"line":581},[3300],{"type":35,"tag":560,"props":3301,"children":3302},{},[3303],{"type":40,"value":1427},{"type":35,"tag":560,"props":3305,"children":3306},{"class":562,"line":590},[3307],{"type":35,"tag":560,"props":3308,"children":3309},{"emptyLinePlaceholder":972},[3310],{"type":40,"value":975},{"type":35,"tag":560,"props":3312,"children":3313},{"class":562,"line":599},[3314],{"type":35,"tag":560,"props":3315,"children":3316},{},[3317],{"type":40,"value":3318},"spec lemma monotonicity(x: num, y: num) {\n",{"type":35,"tag":560,"props":3320,"children":3321},{"class":562,"line":978},[3322],{"type":35,"tag":560,"props":3323,"children":3324},{},[3325],{"type":40,"value":3326},"    requires x \u003C= y;\n",{"type":35,"tag":560,"props":3328,"children":3329},{"class":562,"line":987},[3330],{"type":35,"tag":560,"props":3331,"children":3332},{},[3333],{"type":40,"value":3334},"    ensures sum(x) \u003C= sum(y);\n",{"type":35,"tag":560,"props":3336,"children":3337},{"class":562,"line":996},[3338],{"type":35,"tag":560,"props":3339,"children":3340},{},[3341],{"type":40,"value":3342},"} proof {\n",{"type":35,"tag":560,"props":3344,"children":3345},{"class":562,"line":1005},[3346],{"type":35,"tag":560,"props":3347,"children":3348},{},[3349],{"type":40,"value":3350},"    if (x \u003C y) {\n",{"type":35,"tag":560,"props":3352,"children":3353},{"class":562,"line":1014},[3354],{"type":35,"tag":560,"props":3355,"children":3356},{},[3357],{"type":40,"value":3358},"        assert sum(y - 1) \u003C= sum(y);\n",{"type":35,"tag":560,"props":3360,"children":3361},{"class":562,"line":1022},[3362],{"type":35,"tag":560,"props":3363,"children":3364},{},[3365],{"type":40,"value":3366},"        apply monotonicity(x, y - 1);\n",{"type":35,"tag":560,"props":3368,"children":3369},{"class":562,"line":1031},[3370],{"type":35,"tag":560,"props":3371,"children":3372},{},[3373],{"type":40,"value":3374},"    }\n",{"type":35,"tag":560,"props":3376,"children":3377},{"class":562,"line":1040},[3378],{"type":35,"tag":560,"props":3379,"children":3380},{},[3381],{"type":40,"value":1427},{"type":35,"tag":560,"props":3383,"children":3384},{"class":562,"line":1049},[3385],{"type":35,"tag":560,"props":3386,"children":3387},{"emptyLinePlaceholder":972},[3388],{"type":40,"value":975},{"type":35,"tag":560,"props":3390,"children":3391},{"class":562,"line":1058},[3392],{"type":35,"tag":560,"props":3393,"children":3394},{"emptyLinePlaceholder":972},[3395],{"type":40,"value":975},{"type":35,"tag":560,"props":3397,"children":3398},{"class":562,"line":1066},[3399],{"type":35,"tag":560,"props":3400,"children":3401},{},[3402],{"type":40,"value":3403},"fun sum_up_to(n: u64): u64 { \u002F* iterative impl *\u002F }\n",{"type":35,"tag":560,"props":3405,"children":3406},{"class":562,"line":1075},[3407],{"type":35,"tag":560,"props":3408,"children":3409},{},[3410],{"type":40,"value":3411},"spec sum_up_to {\n",{"type":35,"tag":560,"props":3413,"children":3414},{"class":562,"line":1084},[3415],{"type":35,"tag":560,"props":3416,"children":3417},{},[3418],{"type":40,"value":3419},"    requires n \u003C= 5;\n",{"type":35,"tag":560,"props":3421,"children":3422},{"class":562,"line":1093},[3423],{"type":35,"tag":560,"props":3424,"children":3425},{},[3426],{"type":40,"value":3427},"    ensures result == sum(n);\n",{"type":35,"tag":560,"props":3429,"children":3431},{"class":562,"line":3430},20,[3432],{"type":35,"tag":560,"props":3433,"children":3434},{},[3435],{"type":40,"value":3342},{"type":35,"tag":560,"props":3437,"children":3439},{"class":562,"line":3438},21,[3440],{"type":35,"tag":560,"props":3441,"children":3442},{},[3443],{"type":40,"value":3444},"   forall x,y {sum(x), sum(y)} apply monotonicity(x, y);\n",{"type":35,"tag":560,"props":3446,"children":3448},{"class":562,"line":3447},22,[3449],{"type":35,"tag":560,"props":3450,"children":3451},{},[3452],{"type":40,"value":1427},{"type":35,"tag":351,"props":3454,"children":3456},{"id":3455},"proofs",[3457],{"type":40,"value":3458},"Proofs",{"type":35,"tag":36,"props":3460,"children":3461},{},[3462],{"type":40,"value":3463},"A proof consists of a sequence of\nproof statements together with if-then-else and let bindings.",{"type":35,"tag":36,"props":3465,"children":3466},{},[3467,3469,3475,3476,3482,3483,3489,3490,3496,3497,3503,3504,3510,3511,3517],{"type":40,"value":3468},"Proof statements: ",{"type":35,"tag":43,"props":3470,"children":3472},{"className":3471},[],[3473],{"type":40,"value":3474},"let name = Expr",{"type":40,"value":808},{"type":35,"tag":43,"props":3477,"children":3479},{"className":3478},[],[3480],{"type":40,"value":3481},"if (Expr) Proof else Proof",{"type":40,"value":2096},{"type":35,"tag":43,"props":3484,"children":3486},{"className":3485},[],[3487],{"type":40,"value":3488},"assert Expr",{"type":40,"value":808},{"type":35,"tag":43,"props":3491,"children":3493},{"className":3492},[],[3494],{"type":40,"value":3495},"assume Expr",{"type":40,"value":808},{"type":35,"tag":43,"props":3498,"children":3500},{"className":3499},[],[3501],{"type":40,"value":3502},"apply LemmaInstance",{"type":40,"value":2096},{"type":35,"tag":43,"props":3505,"children":3507},{"className":3506},[],[3508],{"type":40,"value":3509},"forall QuantifierDecls [Patterns] apply LemmaInstance",{"type":40,"value":2096},{"type":35,"tag":43,"props":3512,"children":3514},{"className":3513},[],[3515],{"type":40,"value":3516},"calc (Expr { RelOp Expr })",{"type":40,"value":487},{"type":35,"tag":36,"props":3519,"children":3520},{},[3521],{"type":40,"value":3522},"A proof block can be attached to any specification block as postfix to that block, for example:",{"type":35,"tag":549,"props":3524,"children":3527},{"className":3525,"code":3526,"language":40},[2215],"spec sum_to_n {\n  ensures result == sum(n);\n} proof {\n  forall x: u64, y: u64 apply Monotonicity(x, y);\n}  \n",[3528],{"type":35,"tag":43,"props":3529,"children":3530},{"__ignoreMap":554},[3531],{"type":40,"value":3526},{"type":35,"tag":36,"props":3533,"children":3534},{},[3535],{"type":40,"value":3536},"A proof is translated by mapping it to a sequence of assumes\u002Fasserts at the\nverification entry points of a function.",{"type":35,"tag":395,"props":3538,"children":3539},{},[3540,3545],{"type":35,"tag":399,"props":3541,"children":3542},{},[3543],{"type":40,"value":3544},"The split statement is translated by creating different verification variants for each value split\nwith according assumptions of the value at the split point and otherwise identical content.",{"type":35,"tag":399,"props":3546,"children":3547},{},[3548],{"type":40,"value":3549},"The apply statement is translated by injecting pre\u002Fpost conditions of the (expected to be proven) lemma.\nThis is very similar like calling an opaque function in Move code.",{"type":35,"tag":351,"props":3551,"children":3553},{"id":3552},"lemmas",[3554],{"type":40,"value":3555},"Lemmas",{"type":35,"tag":36,"props":3557,"children":3558},{},[3559],{"type":40,"value":3560},"A Lemma is a member of a specification block, similar like a spec function. Its\nuser syntax is:",{"type":35,"tag":549,"props":3562,"children":3565},{"className":3563,"code":3564,"language":40},[2215],"spec fun sum(n: u64): u64 {\n    if (n == 0) { 0 } else { n + sum(n - 1) }\n}\nspec lemma sum_monotonicity(x: num, y: num) {\n    requires x \u003C= y;\n    ensures sum(x) \u003C= sum(y);\n} proof {\n    if (x \u003C y) {\n        assert sum(y - 1) \u003C= sum(y);\n        apply sum_monotonicity(x, y - 1);\n    }\n}\n",[3566],{"type":35,"tag":43,"props":3567,"children":3568},{"__ignoreMap":554},[3569],{"type":40,"value":3564},{"type":35,"tag":36,"props":3571,"children":3572},{},[3573,3575,3580,3582,3587],{"type":40,"value":3574},"Or inside a ",{"type":35,"tag":43,"props":3576,"children":3578},{"className":3577},[],[3579],{"type":40,"value":132},{"type":40,"value":3581}," block (the keyword ",{"type":35,"tag":43,"props":3583,"children":3585},{"className":3584},[],[3586],{"type":40,"value":2635},{"type":40,"value":3588},", not a module name):",{"type":35,"tag":549,"props":3590,"children":3593},{"className":3591,"code":3592,"language":40},[2215],"spec module {\n  fun sum ...\n  lemma sum_monotonicity ...\n}\n",[3594],{"type":35,"tag":43,"props":3595,"children":3596},{"__ignoreMap":554},[3597],{"type":40,"value":3592},{"type":35,"tag":36,"props":3599,"children":3600},{},[3601,3605,3606,3611,3613,3617,3619,3624,3626,3631,3633,3638,3640,3645,3647,3652],{"type":35,"tag":62,"props":3602,"children":3603},{},[3604],{"type":40,"value":2044},{"type":40,"value":2287},{"type":35,"tag":43,"props":3607,"children":3609},{"className":3608},[],[3610],{"type":40,"value":2658},{"type":40,"value":3612}," always targets a ",{"type":35,"tag":473,"props":3614,"children":3615},{},[3616],{"type":40,"value":1833},{"type":40,"value":3618}," named ",{"type":35,"tag":43,"props":3620,"children":3622},{"className":3621},[],[3623],{"type":40,"value":2666},{"type":40,"value":3625},".\nThere is no ",{"type":35,"tag":43,"props":3627,"children":3629},{"className":3628},[],[3630],{"type":40,"value":2650},{"type":40,"value":3632}," syntax. Module-level items (helper\nfunctions, lemmas) go inside ",{"type":35,"tag":43,"props":3634,"children":3636},{"className":3635},[],[3637],{"type":40,"value":132},{"type":40,"value":3639},". Lemmas are ",{"type":35,"tag":62,"props":3641,"children":3642},{},[3643],{"type":40,"value":3644},"not valid",{"type":40,"value":3646},"\ninside function spec blocks (",{"type":35,"tag":43,"props":3648,"children":3650},{"className":3649},[],[3651],{"type":40,"value":210},{"type":40,"value":694},{"type":35,"tag":36,"props":3654,"children":3655},{},[3656,3657,3663,3665,3671,3673,3678],{"type":40,"value":1271},{"type":35,"tag":43,"props":3658,"children":3660},{"className":3659},[],[3661],{"type":40,"value":3662},"spec lemma",{"type":40,"value":3664}," shortcut is sugar for ",{"type":35,"tag":43,"props":3666,"children":3668},{"className":3667},[],[3669],{"type":40,"value":3670},"spec module { lemma ... }",{"type":40,"value":3672},", analogous\nto the ",{"type":35,"tag":43,"props":3674,"children":3676},{"className":3675},[],[3677],{"type":40,"value":2327},{"type":40,"value":3679}," shortcut for helper functions.",{"type":35,"tag":36,"props":3681,"children":3682},{},[3683],{"type":40,"value":3684},"It has a parameter list like a spec function (but no return value) followed by a\nspecification block (with requires, ensures, and pragmas the only allowed conditions).\nAttached to this is an (optional) proof.",{"type":35,"tag":36,"props":3686,"children":3687},{},[3688],{"type":40,"value":3689},"Lemma names are in a separate namespace. They are scoped to modules,\nsimilar like specification functions. They can only be referenced from\nproof 'apply' statements.",{"type":35,"tag":52,"props":3691,"children":3693},{"id":3692},"verification",[3694],{"type":40,"value":3695},"Verification",{"type":35,"tag":351,"props":3697,"children":3699},{"id":3698},"verification-tool",[3700],{"type":40,"value":3701},"Verification Tool",{"type":35,"tag":36,"props":3703,"children":3704},{},[3705,3706,3712],{"type":40,"value":1938},{"type":35,"tag":43,"props":3707,"children":3709},{"className":3708},[],[3710],{"type":40,"value":3711},"move_package_verify",{"type":40,"value":3713}," to run the Move Prover on a package and\nformally verify its specifications:",{"type":35,"tag":395,"props":3715,"children":3716},{},[3717,3736],{"type":35,"tag":399,"props":3718,"children":3719},{},[3720,3722,3727,3729,3734],{"type":40,"value":3721},"Call with ",{"type":35,"tag":43,"props":3723,"children":3725},{"className":3724},[],[3726],{"type":40,"value":1698},{"type":40,"value":3728}," set to the package directory and ",{"type":35,"tag":43,"props":3730,"children":3732},{"className":3731},[],[3733],{"type":40,"value":234},{"type":40,"value":3735}," set to\n5.",{"type":35,"tag":399,"props":3737,"children":3738},{},[3739],{"type":40,"value":3740},"The tool returns \"verification succeeded\" when all specs hold, or a diagnostic with a\ncounterexample when a spec fails.",{"type":35,"tag":3742,"props":3743,"children":3745},"h4",{"id":3744},"narrowing-scope-with-filters",[3746],{"type":40,"value":3747},"Narrowing scope with filters",{"type":35,"tag":36,"props":3749,"children":3750},{},[3751,3752,3757],{"type":40,"value":1669},{"type":35,"tag":43,"props":3753,"children":3755},{"className":3754},[],[3756],{"type":40,"value":100},{"type":40,"value":3758}," parameter to restrict the verification scope:",{"type":35,"tag":395,"props":3760,"children":3761},{},[3762,3785],{"type":35,"tag":399,"props":3763,"children":3764},{},[3765,3770,3772,3777,3779,3784],{"type":35,"tag":62,"props":3766,"children":3767},{},[3768],{"type":40,"value":3769},"Single function:",{"type":40,"value":3771}," set ",{"type":35,"tag":43,"props":3773,"children":3775},{"className":3774},[],[3776],{"type":40,"value":100},{"type":40,"value":3778}," to ",{"type":35,"tag":43,"props":3780,"children":3782},{"className":3781},[],[3783],{"type":40,"value":1849},{"type":40,"value":487},{"type":35,"tag":399,"props":3786,"children":3787},{},[3788,3793,3794,3799,3800,3805],{"type":35,"tag":62,"props":3789,"children":3790},{},[3791],{"type":40,"value":3792},"Single module:",{"type":40,"value":3771},{"type":35,"tag":43,"props":3795,"children":3797},{"className":3796},[],[3798],{"type":40,"value":100},{"type":40,"value":3778},{"type":35,"tag":43,"props":3801,"children":3803},{"className":3802},[],[3804],{"type":40,"value":1984},{"type":40,"value":487},{"type":35,"tag":3742,"props":3807,"children":3809},{"id":3808},"excluding-targets",[3810],{"type":40,"value":3811},"Excluding targets",{"type":35,"tag":36,"props":3813,"children":3814},{},[3815,3816,3821],{"type":40,"value":1669},{"type":35,"tag":43,"props":3817,"children":3819},{"className":3818},[],[3820],{"type":40,"value":252},{"type":40,"value":3822}," parameter to skip specific functions or modules while\nverifying the rest of the scope:",{"type":35,"tag":395,"props":3824,"children":3825},{},[3826,3848],{"type":35,"tag":399,"props":3827,"children":3828},{},[3829,3834,3835,3840,3841,3847],{"type":35,"tag":62,"props":3830,"children":3831},{},[3832],{"type":40,"value":3833},"Exclude function(s):",{"type":40,"value":3771},{"type":35,"tag":43,"props":3836,"children":3838},{"className":3837},[],[3839],{"type":40,"value":252},{"type":40,"value":3778},{"type":35,"tag":43,"props":3842,"children":3844},{"className":3843},[],[3845],{"type":40,"value":3846},"[\"module_name::function_name\"]",{"type":40,"value":487},{"type":35,"tag":399,"props":3849,"children":3850},{},[3851,3856,3857,3862,3863,3869],{"type":35,"tag":62,"props":3852,"children":3853},{},[3854],{"type":40,"value":3855},"Exclude module(s):",{"type":40,"value":3771},{"type":35,"tag":43,"props":3858,"children":3860},{"className":3859},[],[3861],{"type":40,"value":252},{"type":40,"value":3778},{"type":35,"tag":43,"props":3864,"children":3866},{"className":3865},[],[3867],{"type":40,"value":3868},"[\"module_name\"]",{"type":40,"value":487},{"type":35,"tag":36,"props":3871,"children":3872},{},[3873,3875,3880,3882,3887,3888,3893],{"type":40,"value":3874},"Exclusions take precedence over the ",{"type":35,"tag":43,"props":3876,"children":3878},{"className":3877},[],[3879],{"type":40,"value":100},{"type":40,"value":3881}," scope — a target that matches both\n",{"type":35,"tag":43,"props":3883,"children":3885},{"className":3884},[],[3886],{"type":40,"value":100},{"type":40,"value":861},{"type":35,"tag":43,"props":3889,"children":3891},{"className":3890},[],[3892],{"type":40,"value":252},{"type":40,"value":3894}," is excluded. This is useful in the \"Fix logical errors\" task to skip timed-out\nfunctions without modifying source files.",{"type":35,"tag":3742,"props":3896,"children":3898},{"id":3897},"setting-timeout",[3899],{"type":40,"value":3900},"Setting timeout",{"type":35,"tag":36,"props":3902,"children":3903},{},[3904],{"type":40,"value":3905},"Verification can be long-running (10 seconds or more). Always explicitly specify a timeout.\nStart with a low timeout of 5 to get quick feedback.\nIncrease the timeout to not more than 10 in the case of\ninvestigating difficult verification problems.",{"type":35,"tag":351,"props":3907,"children":3909},{"id":3908},"diagnosing-verification-failures",[3910],{"type":40,"value":3911},"Diagnosing Verification Failures",{"type":35,"tag":36,"props":3913,"children":3914},{},[3915],{"type":40,"value":3916},"When the prover reports a counterexample or error:",{"type":35,"tag":395,"props":3918,"children":3919},{},[3920,3937,3954,3990,4000],{"type":35,"tag":399,"props":3921,"children":3922},{},[3923,3928,3930,3935],{"type":35,"tag":62,"props":3924,"children":3925},{},[3926],{"type":40,"value":3927},"Postcondition failure",{"type":40,"value":3929},": The ",{"type":35,"tag":43,"props":3931,"children":3933},{"className":3932},[],[3934],{"type":40,"value":167},{"type":40,"value":3936}," clause doesn't hold for some execution path.\nCheck whether an edge case is missing or the condition is too strong.",{"type":35,"tag":399,"props":3938,"children":3939},{},[3940,3945,3947,3952],{"type":35,"tag":62,"props":3941,"children":3942},{},[3943],{"type":40,"value":3944},"Abort condition failure",{"type":40,"value":3946},": An abort path is not covered by ",{"type":35,"tag":43,"props":3948,"children":3950},{"className":3949},[],[3951],{"type":40,"value":175},{"type":40,"value":3953},". Trace which\noperations can abort (arithmetic overflow, missing resource, vector out-of-bounds) and\nadd the missing condition.",{"type":35,"tag":399,"props":3955,"children":3956},{},[3957,3969,3971,3976,3977,3982,3983,3988],{"type":35,"tag":62,"props":3958,"children":3959},{},[3960,3962,3967],{"type":40,"value":3961},"Wrong ",{"type":35,"tag":43,"props":3963,"children":3965},{"className":3964},[],[3966],{"type":40,"value":448},{"type":40,"value":3968}," usage",{"type":40,"value":3970},": Using ",{"type":35,"tag":43,"props":3972,"children":3974},{"className":3973},[],[3975],{"type":40,"value":448},{"type":40,"value":2952},{"type":35,"tag":43,"props":3978,"children":3980},{"className":3979},[],[3981],{"type":40,"value":175},{"type":40,"value":76},{"type":35,"tag":43,"props":3984,"children":3986},{"className":3985},[],[3987],{"type":40,"value":1152},{"type":40,"value":3989}," causes a compilation\nerror. Remove it — those clauses are already evaluated in the pre-state.",{"type":35,"tag":399,"props":3991,"children":3992},{},[3993,3998],{"type":35,"tag":62,"props":3994,"children":3995},{},[3996],{"type":40,"value":3997},"Loop-related failures",{"type":40,"value":3999},": Missing or too-weak loop invariants cause havoced variables.\nStrengthen the invariant to constrain all loop-modified variables.",{"type":35,"tag":399,"props":4001,"children":4002},{},[4003,4008,4010,4014,4016,4021,4022,4027,4029,4035,4037,4040,4042,4048,4049,4153,4156,4158,4164,4165,4168,4173,4175,4178,4183,4185,4191,4192,4198,4199,4205,4207,4210,4215,4217,4222],{"type":35,"tag":62,"props":4004,"children":4005},{},[4006],{"type":40,"value":4007},"Timeout (\"out of resources\")",{"type":40,"value":4009},":",{"type":35,"tag":4011,"props":4012,"children":4013},"br",{},[],{"type":40,"value":4015},"Do not delete, comment out, or weaken any ",{"type":35,"tag":43,"props":4017,"children":4019},{"className":4018},[],[4020],{"type":40,"value":175},{"type":40,"value":76},{"type":35,"tag":43,"props":4023,"children":4025},{"className":4024},[],[4026],{"type":40,"value":167},{"type":40,"value":4028},"\ncondition to resolve a timeout. This includes adding\n",{"type":35,"tag":43,"props":4030,"children":4032},{"className":4031},[],[4033],{"type":40,"value":4034},"pragma aborts_if_is_partial;",{"type":40,"value":4036},", which silently suppresses uncovered abort\npaths. Every condition is assumed semantically correct; removing one hides\nreal properties and makes the specification unsound.",{"type":35,"tag":4011,"props":4038,"children":4039},{},[],{"type":40,"value":4041},"Timeout resolution strategies — try these in order, and iterate\naggressively before resorting to ",{"type":35,"tag":43,"props":4043,"children":4045},{"className":4044},[],[4046],{"type":40,"value":4047},"pragma verify_duration_estimate",{"type":40,"value":4009},{"type":35,"tag":661,"props":4050,"children":4051},{},[4052,4062,4079,4089,4136],{"type":35,"tag":399,"props":4053,"children":4054},{},[4055,4060],{"type":35,"tag":62,"props":4056,"children":4057},{},[4058],{"type":40,"value":4059},"Add data invariants and global update invariants",{"type":40,"value":4061}," to constrain\nresource state. These are checked once per modifying function and then\nassumed at every call site (including inside loops), giving the prover\nfacts for free without recursive helpers. See the inference reference\nfor details on when to use each kind.",{"type":35,"tag":399,"props":4063,"children":4064},{},[4065,4070,4072,4077],{"type":35,"tag":62,"props":4066,"children":4067},{},[4068],{"type":40,"value":4069},"Introduce spec helper functions",{"type":40,"value":4071}," that capture intermediate properties.\nFactor complex ",{"type":35,"tag":43,"props":4073,"children":4075},{"className":4074},[],[4076],{"type":40,"value":167},{"type":40,"value":4078}," into compositions of simpler helpers. Each\nhelper should express one logical step the solver can verify independently.",{"type":35,"tag":399,"props":4080,"children":4081},{},[4082,4087],{"type":35,"tag":62,"props":4083,"children":4084},{},[4085],{"type":40,"value":4086},"Add lemmas",{"type":40,"value":4088}," to establish properties about spec helpers\n(e.g. monotonicity, induction steps) that the solver cannot discover\non its own. Lemmas are proven propositions — do not introduce axioms.",{"type":35,"tag":399,"props":4090,"children":4091},{},[4092,4105,4107,4113,4114,4120,4121,4127,4129,4134],{"type":35,"tag":62,"props":4093,"children":4094},{},[4095,4097,4103],{"type":40,"value":4096},"Add ",{"type":35,"tag":43,"props":4098,"children":4100},{"className":4099},[],[4101],{"type":40,"value":4102},"proof { ... }",{"type":40,"value":4104}," blocks",{"type":40,"value":4106}," to function specs or lemmas to guide\nthe verifier with ",{"type":35,"tag":43,"props":4108,"children":4110},{"className":4109},[],[4111],{"type":40,"value":4112},"assert",{"type":40,"value":808},{"type":35,"tag":43,"props":4115,"children":4117},{"className":4116},[],[4118],{"type":40,"value":4119},"apply",{"type":40,"value":2103},{"type":35,"tag":43,"props":4122,"children":4124},{"className":4123},[],[4125],{"type":40,"value":4126},"calc",{"type":40,"value":4128}," steps. Use ",{"type":35,"tag":43,"props":4130,"children":4132},{"className":4131},[],[4133],{"type":40,"value":4119},{"type":40,"value":4135},"\nto instantiate lemmas at specific points in the proof.",{"type":35,"tag":399,"props":4137,"children":4138},{},[4139,4144,4146,4151],{"type":35,"tag":62,"props":4140,"children":4141},{},[4142],{"type":40,"value":4143},"Rewrite spec expressions",{"type":40,"value":4145}," while preserving their meaning — factor\nout common sub-expressions into ",{"type":35,"tag":43,"props":4147,"children":4149},{"className":4148},[],[4150],{"type":40,"value":1264},{"type":40,"value":4152}," bindings, reorder conjuncts,\nor replace a complex closed-form with a recursive helper connected\nby a lemma.",{"type":35,"tag":4011,"props":4154,"children":4155},{},[],{"type":40,"value":4157},"When you use universal lemma application, always add triggers, as\nin ",{"type":35,"tag":43,"props":4159,"children":4161},{"className":4160},[],[4162],{"type":40,"value":4163},"forall x: u64 {f(x)} apply lemma_for_f(x)",{"type":40,"value":487},{"type":35,"tag":4011,"props":4166,"children":4167},{},[],{"type":35,"tag":62,"props":4169,"children":4170},{},[4171],{"type":40,"value":4172},"Avoid non-linear arithmetic in spec helpers.",{"type":40,"value":4174}," SMT solvers handle linear\narithmetic well but struggle with multiplication, division, or modulo between\ntwo non-constant expressions. Prefer additive recurrences over closed-form\nproducts. If a non-linear closed form is needed, connect it to a recursive\nhelper via a lemma so the solver reasons about each step linearly.",{"type":35,"tag":4011,"props":4176,"children":4177},{},[],{"type":35,"tag":62,"props":4179,"children":4180},{},[4181],{"type":40,"value":4182},"Do not redefine built-in operations as spec helpers.",{"type":40,"value":4184}," The SMT solver\nalready understands ",{"type":35,"tag":43,"props":4186,"children":4188},{"className":4187},[],[4189],{"type":40,"value":4190},"*",{"type":40,"value":808},{"type":35,"tag":43,"props":4193,"children":4195},{"className":4194},[],[4196],{"type":40,"value":4197},"\u002F",{"type":40,"value":808},{"type":35,"tag":43,"props":4200,"children":4202},{"className":4201},[],[4203],{"type":40,"value":4204},"%",{"type":40,"value":4206},", comparisons, and bitwise operations\nnatively. Only introduce a spec helper when it encodes logic the solver\ndoes not have built in — such as a loop accumulation pattern or a\nrecursive data-structure traversal.",{"type":35,"tag":4011,"props":4208,"children":4209},{},[],{"type":35,"tag":62,"props":4211,"children":4212},{},[4213],{"type":40,"value":4214},"Document every function and lemma.",{"type":40,"value":4216}," Add a ",{"type":35,"tag":43,"props":4218,"children":4220},{"className":4219},[],[4221],{"type":40,"value":2363},{"type":40,"value":4223}," doc comment explaining\nwhat property it captures and why it is needed. Place new spec helper\nfunctions below the Move function that introduces them. Place lemmas\ndirectly beneath their helper's declaration.",{"type":35,"tag":52,"props":4225,"children":4227},{"id":4226},"task",[4228],{"type":40,"value":4229},"Task",{"type":35,"tag":36,"props":4231,"children":4232},{},[4233],{"type":40,"value":4234},"Run specification inference workflow for current package.",{"type":35,"tag":4236,"props":4237,"children":4238},"style",{},[4239],{"type":40,"value":4240},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"items":4242,"total":987},[4243,4253,4264,4269,4280,4291,4300],{"slug":553,"name":553,"fn":4244,"description":4245,"org":4246,"tags":4247,"stars":20,"repoUrl":21,"updatedAt":4252},"develop applications on Aptos","Move development on Aptos",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[4248,4251],{"name":4249,"slug":4250,"type":16},"Blockchain","blockchain",{"name":14,"slug":15,"type":16},"2026-07-19T06:03:46.40898",{"slug":4254,"name":4254,"fn":4255,"description":4256,"org":4257,"tags":4258,"stars":20,"repoUrl":21,"updatedAt":4263},"move-check","check Move packages for compilation errors","Check a Move package for compilation errors",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[4259,4262],{"name":4260,"slug":4261,"type":16},"Debugging","debugging",{"name":14,"slug":15,"type":16},"2026-07-19T06:03:09.843322",{"slug":4,"name":4,"fn":5,"description":6,"org":4265,"tags":4266,"stars":20,"repoUrl":21,"updatedAt":22},{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[4267,4268],{"name":18,"slug":19,"type":16},{"name":14,"slug":15,"type":16},{"slug":4270,"name":4270,"fn":4271,"description":4272,"org":4273,"tags":4274,"stars":20,"repoUrl":21,"updatedAt":4279},"move-init","initialize Move workflow routing","Initialize Move workflow routing in the project CLAUDE.md",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[4275,4278],{"name":4276,"slug":4277,"type":16},"Configuration","configuration",{"name":14,"slug":15,"type":16},"2026-07-19T06:03:48.382736",{"slug":4281,"name":4281,"fn":4282,"description":4283,"org":4284,"tags":4285,"stars":20,"repoUrl":21,"updatedAt":4290},"move-prove","verify Move specifications with Move Prover","Run the Move Prover to formally verify specifications",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[4286,4289],{"name":4287,"slug":4288,"type":16},"Testing","testing",{"name":14,"slug":15,"type":16},"2026-07-19T06:03:10.663492",{"slug":4292,"name":4292,"fn":4293,"description":4294,"org":4295,"tags":4296,"stars":20,"repoUrl":21,"updatedAt":4299},"move-replay","replay and debug Aptos transactions","Replay a committed on-chain Aptos transaction locally to debug its outcome. Use when investigating a failed or unexpected transaction, reproducing an abort, or testing a local Move patch against a historical transaction.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[4297,4298],{"name":4260,"slug":4261,"type":16},{"name":14,"slug":15,"type":16},"2026-07-19T06:03:11.562048",{"slug":4301,"name":4301,"fn":4302,"description":4303,"org":4304,"tags":4305,"stars":20,"repoUrl":21,"updatedAt":4308},"move-test","generate unit tests for Move code","Generate unit tests for Move code. Use for test generation, writing tests, or improving coverage.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[4306,4307],{"name":4287,"slug":4288,"type":16},{"name":14,"slug":15,"type":16},"2026-07-19T06:03:11.019744",{"items":4310,"total":4471},[4311,4326,4343,4357,4369,4383,4397,4412,4426,4441,4451,4461],{"slug":4312,"name":4312,"fn":4313,"description":4314,"org":4315,"tags":4316,"stars":1084,"repoUrl":4324,"updatedAt":4325},"analyze-gas-optimization","optimize Aptos Move contracts for gas","Analyze and optimize Aptos Move contracts for gas efficiency, identifying expensive operations and suggesting optimizations. Triggers on: 'optimize gas', 'reduce gas costs', 'gas analysis', 'make contract cheaper', 'gas efficiency', 'analyze gas usage', 'reduce transaction costs'.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[4317,4318,4321],{"name":4249,"slug":4250,"type":16},{"name":4319,"slug":4320,"type":16},"Performance","performance",{"name":4322,"slug":4323,"type":16},"Smart Contracts","smart-contracts","https:\u002F\u002Fgithub.com\u002Faptos-labs\u002Faptos-agent-skills","2026-07-12T08:07:14.117466",{"slug":4327,"name":4327,"fn":4328,"description":4329,"org":4330,"tags":4331,"stars":1084,"repoUrl":4324,"updatedAt":4342},"create-aptos-project","scaffold new Aptos dApp projects","Scaffolds new Aptos projects using npx create-aptos-dapp. Supports fullstack (Vite or Next.js) and contract-only templates with network selection and optional API key. Triggers on: 'build app', 'create app', 'make app', 'new app', 'build dApp', 'create dApp', 'new dApp', 'build project', 'new project', 'create project', 'scaffold', 'start project', 'set up project', 'build me a', 'I want to build', 'make me a', 'help me build'.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[4332,4335,4338,4341],{"name":4333,"slug":4334,"type":16},"Next.js","next-js",{"name":4336,"slug":4337,"type":16},"TypeScript","typescript",{"name":4339,"slug":4340,"type":16},"Vite","vite",{"name":14,"slug":15,"type":16},"2026-07-12T08:07:30.595111",{"slug":4344,"name":4344,"fn":4345,"description":4346,"org":4347,"tags":4348,"stars":1084,"repoUrl":4324,"updatedAt":4356},"deploy-contracts","deploy Move contracts to Aptos networks","Safely deploys Move contracts to Aptos networks (devnet, testnet, mainnet) with pre-deployment verification. Triggers on: 'deploy contract', 'publish to testnet', 'deploy to mainnet', 'how to deploy', 'publish module', 'deployment checklist', 'deploy to devnet'.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[4349,4352,4355],{"name":4350,"slug":4351,"type":16},"Deployment","deployment",{"name":4353,"slug":4354,"type":16},"Engineering","engineering",{"name":4322,"slug":4323,"type":16},"2026-07-12T08:07:16.798352",{"slug":4358,"name":4358,"fn":4359,"description":4360,"org":4361,"tags":4362,"stars":1084,"repoUrl":4324,"updatedAt":4368},"generate-tests","generate test suites for Move contracts","Creates comprehensive test suites for Move contracts with 100% coverage requirement. Triggers on: 'generate tests', 'create tests', 'write test suite', 'test this contract', 'how to test', 'add test coverage', 'write unit tests'.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[4363,4364,4367],{"name":4353,"slug":4354,"type":16},{"name":4365,"slug":4366,"type":16},"QA","qa",{"name":4287,"slug":4288,"type":16},"2026-07-12T08:07:18.0205",{"slug":4370,"name":4370,"fn":4371,"description":4372,"org":4373,"tags":4374,"stars":1084,"repoUrl":4324,"updatedAt":4382},"modernize-move","modernize Move V1 contracts to V2","Detects and modernizes outdated Move V1 syntax, patterns, and APIs to Move V2+. Use when upgrading legacy contracts, migrating to modern syntax, or converting old patterns to current best practices. NOT for writing new contracts (use write-contracts) or fixing bugs.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[4375,4378,4379],{"name":4376,"slug":4377,"type":16},"Code Analysis","code-analysis",{"name":4353,"slug":4354,"type":16},{"name":4380,"slug":4381,"type":16},"Migration","migration","2026-07-12T08:07:10.226223",{"slug":4384,"name":4384,"fn":4385,"description":4386,"org":4387,"tags":4388,"stars":1084,"repoUrl":4324,"updatedAt":4396},"search-aptos-examples","search Aptos reference implementations","Searches aptos-core and daily-move for reference implementations before writing contracts. Triggers on: 'search examples', 'find example', 'check aptos-core', 'is there an example', 'reference implementation', 'how does aptos implement', 'similar contract', 'daily-move'.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[4389,4390,4393],{"name":4249,"slug":4250,"type":16},{"name":4391,"slug":4392,"type":16},"Documentation","documentation",{"name":4394,"slug":4395,"type":16},"Search","search","2026-07-12T08:07:15.382039",{"slug":4398,"name":4398,"fn":4399,"description":4400,"org":4401,"tags":4402,"stars":1084,"repoUrl":4324,"updatedAt":4411},"security-audit","audit Move smart contracts for security","Audits Move contracts for security vulnerabilities before deployment using 7-category checklist. Triggers on: 'audit contract', 'security check', 'review security', 'check for vulnerabilities', 'security audit', 'is this secure', 'find security issues'.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[4403,4406,4407,4410],{"name":4404,"slug":4405,"type":16},"Audit","audit",{"name":4376,"slug":4377,"type":16},{"name":4408,"slug":4409,"type":16},"Security","security",{"name":4322,"slug":4323,"type":16},"2026-07-12T08:07:11.680215",{"slug":4413,"name":4413,"fn":4414,"description":4415,"org":4416,"tags":4417,"stars":1084,"repoUrl":4324,"updatedAt":4425},"smoothsend-gasless","sponsor gas fees for Aptos dApps","How to sponsor gas fees for Aptos dApp users using SmoothSend. Paid commercial service: free on testnet, credit-based on mainnet. Covers 3-line wallet adapter integration (transactionSubmitter), Script Composer for fee-in-token stablecoin transfers. Triggers on: 'gasless', 'sponsor gas', 'users pay no APT', 'transactionSubmitter', 'SmoothSend', 'fee payer', 'pay gas for users', 'no gas required'.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[4418,4421,4424],{"name":4419,"slug":4420,"type":16},"API Development","api-development",{"name":4422,"slug":4423,"type":16},"Payments","payments",{"name":14,"slug":15,"type":16},"2026-07-12T08:07:31.843242",{"slug":4427,"name":4427,"fn":4428,"description":4429,"org":4430,"tags":4431,"stars":1084,"repoUrl":4324,"updatedAt":4440},"ts-sdk-account","manage Aptos accounts with TS SDK","How to create and use Account (signer) in @aptos-labs\u002Fts-sdk. Covers Account.generate(), fromPrivateKey(), fromDerivationPath(), Ed25519 vs SingleKey vs MultiKey vs Keyless, serialization (fromHex\u002FtoHex). Triggers on: 'Account.generate', 'Account.fromPrivateKey', 'Ed25519PrivateKey', 'SDK account', 'mnemonic', 'SingleKeyAccount', 'KeylessAccount'.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[4432,4435,4436,4439],{"name":4433,"slug":4434,"type":16},"Auth","auth",{"name":4249,"slug":4250,"type":16},{"name":4437,"slug":4438,"type":16},"SDK","sdk",{"name":4336,"slug":4337,"type":16},"2026-07-12T08:07:29.297415",{"slug":4442,"name":4442,"fn":4443,"description":4444,"org":4445,"tags":4446,"stars":1084,"repoUrl":4324,"updatedAt":4450},"ts-sdk-address","manage AccountAddress in Aptos TypeScript SDK","How to create and use AccountAddress in @aptos-labs\u002Fts-sdk. Covers address format (AIP-40), from\u002FfromString\u002FfromStrict, special addresses, LONG vs SHORT form, and derived addresses (object, resource, token, user-derived). Triggers on: 'AccountAddress', 'AccountAddress.from', 'AIP-40', 'derived address', 'createObjectAddress', 'createResourceAddress', 'createTokenAddress'.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[4447,4448,4449],{"name":4249,"slug":4250,"type":16},{"name":4437,"slug":4438,"type":16},{"name":4336,"slug":4337,"type":16},"2026-07-12T08:07:26.430378",{"slug":4452,"name":4452,"fn":4453,"description":4454,"org":4455,"tags":4456,"stars":1084,"repoUrl":4324,"updatedAt":4460},"ts-sdk-client","configure Aptos SDK clients","How to create and configure the Aptos client (Aptos, AptosConfig) in @aptos-labs\u002Fts-sdk. Covers Network, fullnode\u002Findexer\u002Ffaucet URLs, singleton pattern, and Bun compatibility. Triggers on: 'Aptos client', 'AptosConfig', 'SDK client', 'client setup', 'new Aptos(', 'Network.TESTNET', 'Network.MAINNET'.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[4457,4458,4459],{"name":4419,"slug":4420,"type":16},{"name":4437,"slug":4438,"type":16},{"name":4336,"slug":4337,"type":16},"2026-07-12T08:07:21.933342",{"slug":4462,"name":4462,"fn":4463,"description":4464,"org":4465,"tags":4466,"stars":1084,"repoUrl":4324,"updatedAt":4470},"ts-sdk-transactions","manage Aptos blockchain transactions","How to build, sign, submit, and simulate transactions in @aptos-labs\u002Fts-sdk. Covers build.simple(), signAndSubmitTransaction(), waitForTransaction(), simulate, sponsored (fee payer), and multi-agent. Triggers on: 'build.simple', 'signAndSubmitTransaction', 'transaction.build', 'waitForTransaction', 'signAsFeePayer', 'SDK transaction', 'sponsored transaction', 'multi-agent transaction'.",{"slug":8,"name":9,"logoUrl":10,"githubOrg":11},[4467,4468,4469],{"name":4419,"slug":4420,"type":16},{"name":4336,"slug":4337,"type":16},{"name":14,"slug":15,"type":16},"2026-07-12T08:07:23.774257",24]