ek9_query_mutex_payload
Answers first: status, summary {bodies, contained, mayEscape, unknown}, findingCount, then findings[] {file, line, inConstruct, payloadType, locks, escape, sites[] with via chain and origin}.
When to use it
'Does any MutexLock payload escape its critical section' is one call with no arguments - every MutexKey body, with the chain to whoever keeps the reference.
When not to use it
- whether ONE named structure is touched by ONE callable (use
ek9_query_data_touch, which anchors on a callable and tracks a named parameter) - lock ORDER / deadlock risk rather than payload containment (that is E08252/E08255 and
ek9_query_deadlock_chain) - CHANGING code — this is a read-only enquiry with no fix
Details
summary {bodies, contained, mayEscape, unknown} counts EVERY MutexKey body, so 'N of M contained' can be stated; findings[] is the escaping subset. Each finding carries {file, line, column (the MutexKey body, 0-based column), inConstruct / inConstructFqn (the named method/function declaring it, in callable-identity form — joins ek9_query_call_graph), payloadType (as written: 'List of String'), locks[] ({stableId, displayName} of the MutexLock it runs under — the same ids ek9_query_lock_identity lists), escape (may-escape / contained / unknown), sites[], unknowns[]}. inConstruct is absent when phase 8 lock analysis did not run (the default compile reaches it); locks[] is absent when no enter() call was paired with the body. Each site has {file, line, kind (escape-store / returns-alias), path (where the reference lands), root {name, role: this/field/parameter/capture — the root of path in the WRITER's frame}, via[] (the callee chain, by RESOLVED signature) and origin {file, line} (where it is actually stored)}. A site with NO via and NO origin IS the write, in the body itself; capture means the body captured that variable, so the object is the caller's and the fix is in the body. hints{} explains the verdicts and fields. ':=:' / ':~:' / ':^:' copy CONTENT and are not reported — they are what E08258 tells you to use. ⚠️ The copy family is SHALLOW: the container is independent but its ELEMENTS are shared, so copying a list of mutable records out of a lock still shares those records.
Arguments
| Argument | Type | Required | What it is |
|---|---|---|---|
includeUnknown | boolean | Also report MutexKey bodies whose escape verdict is 'unknown' — an opaque callee, or the payload handed to a function value. Off by default so the list stays actionable. |
Recorded calls
Real calls, recorded against small projects and checked on every build - a changed answer fails it.
Escaping payload
Request
{ }
Response
{
"findingCount" : 2,
"findings" : [ {
"column" : 21,
"escape" : "may-escape",
"file" : "locks.ek9",
"inConstruct" : "Box.exfiltrate(Stash)",
"inConstructFqn" : "probe.mutex.payload::Box.exfiltrate(probe.mutex.payload::Stash)",
"line" : 26,
"locks" : [ {
"displayName" : "probe.mutex.payload::lockedItems",
"stableId" : "field:probe.mutex.payload::lockedItems@22:6"
} ],
"payloadType" : "List of String",
"sites" : [ {
"file" : "locks.ek9",
"kind" : "escape-store",
"line" : 27,
"origin" : {
"file" : "locks.ek9",
"line" : 17
},
"path" : "held",
"root" : {
...
Cut short here: 46 more lines. The whole recorded call.