feat(model): phase 2 measured (weights v1) and carried reported by the evidence branch

budget_at_recall by a real evidence pass over every region: pmpro 391 -> 116, wpstatistics 504 -> 223,
mwwpform 513 -> 292, vampi 16 -> 16. The gate (< 50) is not met. pmpro's CVE is inside its 121 tier-4
regions; WP Statistics's and MW WP Form's are one tier low because `carried` -- stage one of the
two-stage join -- was not reported as evidence. taint.sc now reports it where a sink exists, and the
vector reads the query's answer when given.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01T7XD7x5KonMdmGRkp63EQG
This commit is contained in:
Marius Ciepluch
2026-09-11 11:47:06 +02:00
co-authored by Claude Fable 5.1
parent 9f881b433e
commit 1741b6bed6
5 changed files with 192 additions and 1 deletions
+8
View File
@@ -554,11 +554,19 @@
// the same answer for every request of one family and a repository-wide walk per request turned a
// milliseconds-per-pair query into minutes.
val familyInRepo = familyInRepoMemo.getOrElseUpdate(sinksS, cpg.call.exists(c => sinkNames.exists(n => sinkMatches(c, n))))
// `carried`: stage one of the two-stage join, reused as evidence (flow-aware-ranking, phase 2). A field
// read in scope whose assignment is fed by a source, or an array key a registered hook callback fills
// from one -- computed and memoised for the arbiter anyway, and the exact fact that puts
// `_delete_files()` (fed by `$this->attachments`) and `record()` (fed by a filter) where their sources
// say, instead of one tier below every region with a `$_GET` in its own body. Asked only where there
// is a sink to carry to, so the 21,000 tier-0 pairs of a plugin pay nothing for it.
val carried = sinkList.nonEmpty && familyInRepo && (fieldList.nonEmpty || hookList.nonEmpty)
val summary = ujson.Obj(
"kind" -> "summary",
"sinks" -> sinkList.size,
"sourceLocal" -> sourceLocal,
"sourceNear" -> sourceNear,
"carried" -> carried,
"familyInRepo" -> familyInRepo
)
val perSink = sinkList.map { sink =>
+3 -1
View File
@@ -156,7 +156,9 @@ def evidence_from_rows(
source_near=_as_bool(summary.get("sourceNear")),
entry=entry,
access_declared_public=access_declared_public,
carried=carried,
# The query's own answer when it gave one (phase 2: stage one of the two-stage join, reused);
# the caller's otherwise; None where neither knows, which is not False.
carried=_as_bool(summary["carried"]) if "carried" in summary else carried,
bound_names=tuple(bound_names),
)