{
  "isError" : false,
  "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" : {
          "name" : "held",
          "role" : "field"
        },
        "via" : [ "probe.mutex.payload::Stash.keep(org.ek9.lang::List of String)" ]
      } ]
    }, {
      "column" : 21,
      "escape" : "may-escape",
      "file" : "locks.ek9",
      "inConstruct" : "Box.drainInto(Sink)",
      "inConstructFqn" : "probe.mutex.payload::Box.drainInto(probe.mutex.payload::Sink)",
      "line" : 32,
      "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" : 33,
        "path" : "sink.items",
        "root" : {
          "name" : "sink",
          "role" : "capture"
        }
      } ]
    } ],
    "hints" : {
      "copyIsShallow" : "':=:' / ':~:' / ':^:' copy the container, not its elements - a list of mutable records copied out of a lock still shares those records.",
      "may-escape" : "The body hands lockedItem to something that keeps a reference, so the payload can be read and mutated with no lock held. Copy CONTENT out (rtn :=: lockedItem) or mutate lockedItem in place. A site with via[] and originLine: the named callee stores it at the origin - copy before the call, or change the callee. A site with neither: the write is in the body itself, at site.line.",
      "root" : "root.role is where the stored reference lands, in the writer's frame: this (the writer's own object), field (a field of the writer's owner), parameter (beneath a parameter, so the caller shares it), capture (a variable the MutexKey body captured from its enclosing scope - the caller's object, fix in the body).",
      "see" : "E08258 (ek9_explain_error) - the compiler rejects the direct form; this is the rest, traced through callees. Advisory: gates: false.",
      "unknown" : "The payload reached an opaque callee or a function value; retention is not statically knowable, so a human must judge it."
    },
    "meta" : {
      "serverMs" : "<timing>"
    },
    "status" : "ok",
    "summary" : {
      "bodies" : 3,
      "contained" : 1,
      "mayEscape" : 2,
      "unknown" : 0
    }
  },
  "scenario" : "escaping_payload",
  "tool" : "query_mutex_payload"
}
