Executed against Node and the 1be5308 before binary in both tree and required-VM modes. With values = new Array(3) and Object.setPrototypeOf(values, new String("abc")), borrowed Array indexOf("b") and lastIndexOf("b") return -1 rather than 1. includes("b") also wrongly returns false, while includes(undefined) wrongly returns true when all three positions are inherited String characters. The same result occurs at length 1,000,000.
Executed search matrix (length, indexOf, lastIndexOf, includes("b"), includes(undefined)):
Node: [[3,1,1,true,false],[1000000,1,1,true,true]]
zig-js tree and required VM, including the #1069 candidate: [[3,-1,-1,false,true],[1000000,-1,-1,false,true]]
The prototype-presence gate selects sparse own-index scanning because it does not classify virtual String character descriptors as inherited indexed properties. Read/write eligibility should share the complete classification rather than diverge.
Acceptance:
- IndexOf/lastIndexOf/includes search inherited virtual String characters with exact HasProperty/Get ordering and correct missing-vs-inherited-undefined behavior.
- Share String-aware prototype classification across indexed read/write eligibility.
- Pin short/long/deep-prototype, fromIndex, UTF-16, getters/Proxy effects, mutation, no-GIL, TSan, and ReleaseSafe witnesses.
- Long observable traversals poll pending termination and watchdog requests without changing logical AST/bytecode step accounting.
- Exact before/after affected Array corpus and tree/required-VM outputs have no new failures/divergences.
The large-length sparse-path guard must also be audited by execution before this issue closes; do not assume the scan-size threshold is semantically valid. No performance publication is intended.
The guard audit also reproduced a separate threshold failure: an Array of length 5,000,000 with ordinary prototype { 1: "b" } gives Node [1,1] for indexOf/lastIndexOf, but zig-js gives [-1,-1] in both tiers. The scan-size cap cannot authorize skipping inherited properties.
The receiver-side audit is executed too: a getter at own index 0 that creates index 1 makes indexOf return -1 and includes return false where Node returns 1 and true. The descending lastIndexOf witness correctly expects -1 because creation occurs after index 1 was already visited. Eligibility must therefore refuse observable receiver reads as well as inherited reads. Mapped arguments stale reads are a separate shared-helper prerequisite in #1071.