ek9_apply_symbolic_fix
Inserts the 'require <divisor> <> 0' line guard-first (an inline-initialised return becomes '<- rtn as T?' + ':=?'), re-finding the counterexample server-side, and migrates a pinning @Test to assertPanic in the same changeset; answers status, edits[] and summary.
When to use it
After ek9_verify_method reports DIV_BY_ZERO, 'add the guard' is one call with symbol:'safeAverage' - it inserts the 'require <divisor> <> 0' precondition. V1: DIV_BY_ZERO only.
When not to use it
- You want to FIND whether a function is safe, not change it - use
ek9_verify_method(the read-only dual). - You want to PIN the failing boundary as a test rather than fix it - use
ek9_generate_edge_case_tests(mode:'verify' writes a directed test per counterexample). - You want to add a PARAMETER, not a precondition - use
ek9_change_signature(shares the same guard-first return machinery).
Details
V1 scope: DIV_BY_ZERO only (single named-parameter divisor); other obligations (CALLEE_REQUIRE, CONSTRAINED_CONSTRUCTION) are rejected with a message, not a guessed edit. The finding is re-found by re-running the engine at apply time and matched by obligation+witness on the function at line — a drifted or already-discharged line errors, several fixable divisions demand a witness ('<param>=<value>') to pick one, and the require line is derived server-side (no free-text guard param). Pinned-test migration is off-when-unsure: a hand-edited test it does not recognise is left untouched and named for manual migration.
Arguments
| Argument | Type | Required | What it is |
|---|---|---|---|
file | string | The EK9 source file - OPTIONAL when symbol is a construct name; required to anchor on a member or a use site. | |
line | integer | 1-based line of the declaration or a reference - OMIT it and pass symbol:'<name>' to let the tool find the line (a model counting lines in a file miscounts); if you do count, use ek9_read_file(lineNumbers:true). | |
obligation | string | Optional counterexample selector when the function has several findings. V1 accepts only 'DIV_BY_ZERO'. | |
symbol | string | yes | The function (or 'Type.method') to fix - a bare name finds its file workspace-wide; 'mod::name' when the name is declared in two modules. |
witness | string | Optional counterexample selector ('<param>=<value>', e.g. 'quantity=0') when the function has several fixable divisions. |
It also takes the arguments every tool takes.
Recorded calls
Real calls, recorded against small projects and checked on every build - a changed answer fails it. 3 of the 4 recorded are shown.
Apply unsupported obligation
Request
{
"file" : "Maths.ek9",
"line" : 5,
"obligation" : "CALLEE_REQUIRE"
}
Response
{
"conflicts" : [ ],
"edits" : [ ],
"error" : {
"message" : "Apply-fix V1 handles DIV_BY_ZERO only; 'CALLEE_REQUIRE' is not yet supported."
},
"meta" : {
"serverMs" : "<timing>"
},
"status" : "error",
"summary" : "Apply-fix V1 handles DIV_BY_ZERO only; 'CALLEE_REQUIRE' is not yet supported.",
"wouldBeDiagnostics" : [ ],
"written" : false
}
Apply div fix dryrun
Request
{
"dryRun" : true,
"file" : "Maths.ek9",
"line" : 5
}
Response
{
"conflicts" : [ ],
"edits" : [ {
"after" : " <- rtn as Integer?\n require count <> 0\n rtn :=? total / count",
"before" : " <- rtn as Integer: total / count",
"endLine" : 9,
"file" : "Maths.ek9",
"startLine" : 9,
"type" : "replace"
} ],
"meta" : {
"serverMs" : "<timing>"
},
"risk" : {
"crossesModuleBoundary" : false,
"estimatedSeverity" : "trivial",
"fileCount" : 1,
"lineCount" : 1,
"touchesPublicApi" : false,
"touchesTests" : false
},
"status" : "ready",
"summary" : "Add precondition 'require count <> 0' to discharge the division-by-zero.",
"workspaceHash" : "<workspace-hash>",
...
Cut short here: 3 more lines. The whole recorded call.
Apply pure fn assign if unset
Request
{
"dryRun" : true,
"file" : "Maths.ek9",
"line" : 5
}
Response
{
"conflicts" : [ ],
"edits" : [ {
"after" : " <- rtn as Integer?\n require count <> 0\n rtn :=? total / count",
"before" : " <- rtn as Integer: total / count",
"endLine" : 9,
"file" : "Maths.ek9",
"startLine" : 9,
"type" : "replace"
} ],
"meta" : {
"serverMs" : "<timing>"
},
"risk" : {
"crossesModuleBoundary" : false,
"estimatedSeverity" : "trivial",
"fileCount" : 1,
"lineCount" : 1,
"touchesPublicApi" : false,
"touchesTests" : false
},
"status" : "ready",
"summary" : "Add precondition 'require count <> 0' to discharge the division-by-zero.",
"workspaceHash" : "<workspace-hash>",
...
Cut short here: 3 more lines. The whole recorded call.