Parent: #904; related #899 and #918.
The parser rejects direct private-field deletion but misses an optional-chain wrapper. parseUnary checks only .member; parseMemberTail returns .optional_chain for optional accesses. Consequently a class containing delete obj?.#x or delete null?.#x is accepted, and earlier eval statements execute instead of being prevented by the required early SyntaxError.
Example:
var touched = 0;
try { eval('touched = 1; class C { #x; m(o) { delete o?.#x; } }'); }
catch (error) { /* must be SyntaxError, touched must remain 0 */ }ECMAScript 13.5.1.1 explicitly covers private OptionalChain references and parenthesized forms: https://tc39.es/ecma262/2026/multipage/ecmascript-language-expressions.html#sec-delete-operator-static-semantics-early-errors
An 18-case before-fix probe shows eight optional-private early-error violations in both tree-walker and required VM. Node/V8 rejects them; the installed JSC accepts them, so JSC's acceptance must not become the specification oracle here. Two direct-private cases already reject but lose the specific diagnostic and operator location. Eight valid controls cover call results, public/computed outer properties, sequence values, private reads in computed keys, and a public string key spelled '#x'.
Fix the private-reference classification at the delete operator, without recursively rejecting private reads that only supply a value to a valid outer operation. Preserve a specific private-deletion diagnostic and the owned delete-operator position through nested templates. Add script/module and tree/VM early-error non-execution tests, keep every valid control, and measure the pinned class/delete/optional-chain corpus before and after. This is a semantics correction, not a blanket JSC-parity claim.