fix(pre-push-safety-net): take the operation symbol from the call (M1b 12.1)

Admission extracted everything before the first parenthesis, so the operation for
`const preTax = eval(req.body.preTax)` was `const preTax = eval`. No real
declaration can enumerate every assignment a codebase might write, so admission
would have rejected genuine findings on operation_semantics_mismatch. The M1b
demonstration only passed because its declaration listed the assignment spellings.

The symbol is now the trailing qualified callee. Receiver spelling stays part of
it, so `$wpdb->prepare` and `prepare` remain different operations and a declaration
cannot widen from one to the other. A spelling that is not a qualified name, such
as a dynamic `handlers[name](x)`, yields the statement text, matches no declaration
and stays ineligible exactly as before.

Controls cover the assigned call, the receiver distinction, the dynamic spelling,
and that a declaration for a different operation still does not cover it. The
recorded-veto report reads the same helper instead of repeating the extraction.

1,403 tests passed, nine skipped.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_01EmM1j46qgKMh3zqD1QMwEo
This commit is contained in:
Marius Ciepluch
2026-09-17 09:56:59 +02:00
co-authored by Claude Opus 5
parent 6653b6aca8
commit 4ee31142ab
4 changed files with 62 additions and 3 deletions
+2 -1
View File
@@ -37,6 +37,7 @@ from openultrasast.push.policy import (
_grounded_template,
admit_candidates,
operation_provenance,
operation_symbol,
)
FLAG = "--experimental-record-vetoes"
@@ -369,7 +370,7 @@ def _evaluation(delta: CandidateDelta, declarations: Sequence[CapabilityAdmissio
return None
key = CapabilityKey(op.question.language, "unspecified", "unspecified", delta.family, op.mechanism, "unreviewed", semantics)
matching = [declaration for declaration in declarations if declaration.key == key]
symbol = op.operation.partition("(")[0].strip()
symbol = operation_symbol(op.operation)
unavailable: list[str] = []
consequence = repair = None
declaration = matching[0] if len(matching) == 1 else None