{"owner":"sebastienros","repo":"jint","hasSkills":true,"totalSkillsCount":2,"totalTokensCount":7771,"categories":["anthropic-skill","root-instruction"],"hasMcp":false,"mcpConfig":null,"found":[".claude/skills/test262-update/SKILL.md","AGENTS.md"],"skills":{".claude/skills/test262-update/SKILL.md":"---\nname: test262-update\ndescription: Bump Jint's pinned tc39/test262 SHA in Jint.Tests.Test262/Test262Harness.settings.json, triage the upstream commit range for normative changes, run the conformance suite, and fix whatever the new tests expose. Use when asked to update/upgrade test262, bump SuiteGitSha, pull in the latest conformance tests, or investigate a test262 conformance failure after a bump.\n---\n\n# Updating the pinned test262 suite\n\nThe visible change is one line — `SuiteGitSha` in `Jint.Tests.Test262/Test262Harness.settings.json`.\nTreat it as a **code** change anyway. Upstream lands tests for normative changes that Jint has not\nimplemented, and those turn green features red. The whole job is triaging the range before you run\nanything, then fixing the engine — never the tests.\n\n## Ground rules\n\n- **Never edit or \"fix\" a test262 test.** If a test is wrong, the answer is an engine fix or, as a last\n  resort, an `ExcludedFiles` entry.\n- **test262 at the pinned SHA outranks the published prose.** See [Normative changes](#3-normative-changes--the-part-that-actually-costs-time).\n- Exclusions outside `intl402/` must be temporary and carry a comment naming what removes them. Today every\n  `ExcludedFiles` entry is intl402 — keep that invariant.\n- A feature that arrives unimplemented parks in `ExcludedFeatures`; the PR that implements it removes the entry.\n- Work in a worktree, not the primary checkout, and start from a fresh `main`.\n\n## 0. Orient\n\n| Thing | Where |\n| --- | --- |\n| The pin | `Jint.Tests.Test262/Test262Harness.settings.json` → `SuiteGitSha` |\n| Local suite checkout (read-only aid) | `../test262` — `origin` = your fork, `upstream` = `tc39/test262` |\n| Generator | `dotnet test262 generate`, from `Jint.Tests.Test262/.config/dotnet-tools.json` |\n| Generated tests | `Jint.Tests.Test262/Generated/` — **gitignored**, so the committed diff stays one line |\n\nThe runner does **not** read `../test262`. `State.Test262StreamLoader` downloads the suite from GitHub at\n`SuiteGitSha`, so the local checkout exists only so you can read the range. Fetch it anyway — you cannot\ntriage without it.\n\nThe `GenerateTestSuite` MSBuild target hashes the settings file and the tool manifest into\n`Generated/.settings.hash`. Change any byte of either and the next build wipes `Generated/` and regenerates.\nSo: never pass `--no-build`, and if you suspect a stale generation, check the hash file rather than guessing.\n\n## 1. Establish the range\n\n```bash\ncd ../test262 && git fetch upstream\ngit log --oneline <pinned-sha>..upstream/main            # or ..<target-sha> if one was given\ngit diff <pinned-sha>..upstream/main -- features.txt\ngit diff --name-only <pinned-sha>..upstream/main | grep -v '^test/'\n```\n\n**Order commits by ancestry, never by author date.** test262 merges rebased branches, so a commit *authored*\nearlier routinely lands on top of one authored later — a real bump had `3655e746` (authored 08-03) sitting\nabove `be13516f` (authored 08-07). Use `--pretty='%h %cd %s'` or `git merge-base --is-ancestor` when the\nordering matters, and confirm the true remote tip with `git ls-remote https://github.com/tc39/test262.git main`.\n\n## 2. Triage every commit\n\nRead the commits, not just the changed-file list.\n\n| Signal | Meaning |\n| --- | --- |\n| only `.github/**`, `tools/**`, `package.json` | infra — zero impact on the run |\n| `features.txt` gained a line | a new feature; if Jint lacks it, it parks in `ExcludedFeatures` with a comment |\n| `src/**.case` / `src/**.template` | procedurally generated tests changed; read the generated output, not the template |\n| new files under `test/built-ins/**` or `test/language/**` | **the risky class** — go to step 3 |\n| a commit message naming a proposal, \"normative\", or an `ecma262#NNNN` | **stop and read the algorithm diff** |\n\nFor a small range, just read the new tests — `git show <sha>:test/path/to/new-test.js`. A test's `info:` block\nusually quotes the numbered algorithm verbatim, which is the fastest way to see what changed and the most\nreliable way to get argument-validation order right.\n\nFor each new behavioural test, check the engine **before** running the suite. `Jint.Repl` turns a 3-minute\nsuite run into a 10-second answer:\n\n```bash\ndotnet run --project Jint.Repl -c Release -- -f scratch.js -t 10   # always pass -t\n```\n\nWrite the assertions as plain `if (…) throw new Error('FAIL …')` — the REPL has no test262 harness. Strip the\n`$DONOTEVALUATE()` / `includes:` lines; for `flags: [async]` tests, assert on `.then(...)` callbacks.\n\n## 3. Normative changes — the part that actually costs time\n\n**The published spec can be behind test262.** A normative PR that reaches consensus gets test262 coverage\nwhile `tc39.es/ecma262` still renders the old algorithm, and an already-merged proposal's own page\n(`tc39.es/proposal-*/`) is frozen at its pre-merge text and will confidently show you the wrong steps. Both\nhappened on the `Promise.try` bump: the proposal page and the living spec agreed with each other and with\nJint, and all three were what the new tests were written to reject.\n\nFind the real change through the repo, not the rendered spec:\n\n```bash\ngh api -X GET search/issues -f q='repo:tc39/ecma262 <feature> <keyword>' \\\n  --jq '.items[] | \"\\(.number) \\(.state) \\(.title)\"'\ngh pr view <n> --repo tc39/ecma262 --json title,state,mergedAt,labels\ngh pr diff <n> --repo tc39/ecma262        # the spec.html algorithm diff is the authority\n```\n\nLabels tell you the status: `has consensus` + `needs implementations` means implement it. `mergedAt: null` is\n**not** a reason to skip — AGENTS.md is explicit that where prose and test262 disagree, test262 at the pinned\nSHA wins.\n\nWhen you implement one:\n\n- Cite the document that owns the feature now. A merged proposal moves to `https://tc39.es/ecma262/#sec-...`;\n  the anchors get renamed on the way in.\n- Add a `<remarks>` naming the normative PR, so the next reader knows why the code and the current published\n  prose disagree.\n- **Re-check the paths the reorder newly reaches.** Moving a step can expose a latent bug that the old\n  ordering made unreachable — see the gotchas below, where hoisting a call above a capability construction\n  turned a dormant `Promise.try()` crash into a live one.\n\n## 4. Bump, build, run\n\n```bash\n# edit SuiteGitSha, then:\ndotnet test -c Release Jint.Tests.Test262/Jint.Tests.Test262.csproj\n```\n\nThe build regenerates before it compiles; no separate generate step. ~3 minutes, ~99.9k tests. No runner\ntimeout needed — the engine defaults to 30 s per test.\n\nVerify the regeneration actually happened rather than trusting a green run over a stale `Generated/`:\n\n```bash\ngrep -c \"<new-test-name>\" Jint.Tests.Test262/Generated/Tests262Harness.Tests.language.generated.cs\n```\n\nA negative parse test appears **twice** per file (strict + sloppy). Deleted upstream tests should be gone.\n\nThen, because a spec fix moves engine behaviour that unit tests pin:\n\n```bash\ndotnet test -c Release Jint.Tests/Jint.Tests.csproj\ndotnet test -c Release Jint.Tests.PublicInterface/Jint.Tests.PublicInterface.csproj\n```\n\n## 5. Fixing what fails\n\nFailure output contains the failing script — strip the line numbers to reproduce it in `Jint.Repl`. Put a\nregression test in `Jint.Tests` for anything test262 does **not** cover (test262 tests the spec, not Jint's\ninternals; a crash on an input no test262 test exercises still needs a pin).\n\n## 6. Decide whether there is a PR at all\n\nIf the suite is green with only the pin moved, there is nothing to ship but a one-line pin bump — say so and\nask before opening a PR. A bump that needs engine fixes is a real PR: pin + fix + regression tests, targeting\n`sebastienros/jint` `main`.\n\n```bash\ngh pr create --repo sebastienros/jint --head <you>:<branch> --base main\n```\n\nKeeping the local suite fork current is a separate, optional courtesy:\n\n```bash\ncd ../test262 && git fetch upstream && git merge --ff-only upstream/main   # then push origin main if wanted\n```\n\n## Gotchas this task has actually hit\n\n- **Author date lies about ordering.** `%ad` is not topology; use `%cd` or `--is-ancestor`.\n- **The proposal page is frozen at merge.** `tc39.es/proposal-promise-try/` still shows the pre-normative\n  algorithm. Never cite it as current for a merged feature.\n- **`spec.html` is too big for a fetch tool.** Asking a fetcher for one section of the living spec returns a\n  truncated prefix and a confident \"not found\". Go through `gh pr diff` instead.\n- **A reorder exposes latent bugs.** `Promise.try` moved `NewPromiseCapability` after the callback call; the\n  argument-slicing that the old ordering never reached with zero arguments then crashed.\n- **`arguments.AsSpan()` is a trap in a built-in.** `ExpressionCache.ArgumentListEvaluation` hands the callee\n  `Unsafe.As<JsValue[]>(object?[])` whenever the argument list is fully cached — *including the zero-argument\n  case* — so `AsSpan()` throws `ArrayTypeMismatchException` (\"Attempted to access an element as a type\n  incompatible with the array\"). Use `arguments.Skip(n)`, which copies element-wise and returns `[]` when\n  there is nothing to take.\n- **`JsValue.Call` on a non-callable throws a CLR `ArgumentException`, not a JS `TypeError`.** Where the spec\n  says `Call(F, V, args)`, write `GetCallable(f).Call(...)` so the failure is a `JavaScriptException` your\n  `Completion` handling can turn into a rejection.\n- **`Promise`-shaped fixes need the abrupt path checked too.** `Completion(...)` wrapping means a throw\n  inside the step becomes a rejection, while a throw from a step *outside* it propagates to the caller. Tests\n  distinguish the two (`ctx-non-ctor.js` expects a synchronous `TypeError`; `throws.js` expects a rejection).\n","AGENTS.md":"# Agent Instructions for Jint\n\nJint is a JavaScript interpreter for .NET. It parses JavaScript using the Acornima library (AST), then interprets it directly — no bytecode generation or DLR usage. The pipeline is `Acornima parser → AST → interpreter → runtime → interop`, each AST node wrapped once in a `Jint*` interpreter class that `Engine` walks; the three stages, those wrapper classes and what they return — `Completion` for a statement, `JsValue` or `Reference` for an expression — are in [`Jint/Runtime/Interpreter/AGENTS.md`](Jint/Runtime/Interpreter/AGENTS.md#the-execution-pipeline).\n\nThis is the canonical instruction file for every agent working on this repository; `CLAUDE.md` imports it. Target and compare work against the **`main`** branch, which is also the PR target.\n\n## How these instructions are laid out\n\nThis file is the entry point and is kept small: it holds what every agent needs before its first edit,\nwhatever that edit turns out to be. Everything else lives in an `AGENTS.md` beside the code it governs.\n**Read the file on the row matching what you are about to do, before you touch that code.**\n\n| If you are about to… | Read first | What is in it, and what a violation costs |\n| --- | --- | --- |\n| change a signature or observable behaviour under `Jint/`, or anything outliving one evaluation — `Prepared<T>`, `Options`, a snapshot, the event loop, an `*Async` entry | [`Jint/AGENTS.md`](Jint/AGENTS.md) | The key runtime types, the namespace map, the engine-source conventions (type co-location, the unsigned-cast bounds check, the code patterns, visibility), and where the frozen-contract table lives. Cost: a silent breaking change for embedders, or one engine's state leaking into another through a shared `Prepared<Script>`. |\n| implement or change an ECMAScript built-in, intrinsic, coercion rule or new syntax | [`Jint/Native/AGENTS.md`](Jint/Native/AGENTS.md) | Which spec document is authoritative, and that test262 beats prose. Cost: implementing a dated snapshot or a compatibility table instead of the living spec — or un-gating a web API that must stay opt-in. |\n| touch `ObjectInstance`, a property descriptor, a property-access lane, or anything a host subclasses | [`Jint/Native/Object/AGENTS.md`](Jint/Native/Object/AGENTS.md), and [`Jint/Runtime/Descriptors/AGENTS.md`](Jint/Runtime/Descriptors/AGENTS.md) for the descriptor itself | The subclassing cliff, `PropertyAccessSemantics`, host-contract verification, `ArrayLikeObject` and the host-object shapes one pointer on, who may reach a new fast lane. Cost: sorting every embedder into a slow path they cannot see or escape. |\n| touch CLR interop — wrappers, converters, reference resolvers, dictionary-backed reads, a host `ProxyHandler`, a CLR exception crossing into script, `[JsAccessible]`, a trimming or AOT annotation | [`Jint/Runtime/Interop/AGENTS.md`](Jint/Runtime/Interop/AGENTS.md), plus [`Jint.AotExample/AGENTS.md`](Jint.AotExample/AGENTS.md) for the native leg | Which host registrations silently disable a compiled lane engine-wide, the immutable-crossing promise, why a generated accessor is a compile-time copy of the run-time compiled one, and which generic instantiations degrade rather than throw. Cost: an engine-wide deoptimisation nobody can see, stale reads, or an `IsAotCompatible` claim nothing runs. |\n| change either Roslyn source generator, or an attribute one of them reads | [`Jint.SourceGenerators/AGENTS.md`](Jint.SourceGenerators/AGENTS.md) | Why there are two analyzer assemblies and only one may ever be packed, the consumer-facing Roslyn pin a bump breaks silently, the value-equality the incremental model rests on, and why accepting a snapshot is the only review the emitted C# gets. Cost: a package whose first build error is in code the consumer never wrote. |\n| add or change a statement/expression handler, a fast path in one, coverage, or anything published onto the AST or a `Prepared<T>` | [`Jint/Runtime/Interpreter/AGENTS.md`](Jint/Runtime/Interpreter/AGENTS.md) | Engine-affine vs shareable state and the AST `UserData` invariant, why coverage counters cannot live on a handler node, and what a warmed call site retains. Cost: a fast path that silently stops being counted, or an engine pinning a host object for its lifetime. |\n| touch module loading, linking, evaluation, or a module's location | [`Jint/Runtime/Modules/AGENTS.md`](Jint/Runtime/Modules/AGENTS.md) | The load phase, which failures become rejections and which must stay fatal, the three host entry points and which one deadlocks, `ModuleFactory.LocationOf`. Cost: a widened `catch` turns a constraint into a rejection that bounds nothing. |\n| touch anything bounding execution — statements, time, memory, recursion, cancellation | [`Jint/Constraints/AGENTS.md`](Jint/Constraints/AGENTS.md) | How limits and CLR access are configured, what disarms the tight-loop lane, what a fan-out brackets, why the cancellation cadence is engine state, how `MaxRecursionDepth` counts, saturated sentinels. Cost: a limit that no longer limits. |\n| write a call site needing an API `net472` / `netstandard2.0` / `netstandard2.1` lacks | [`Jint/Extensions/AGENTS.md`](Jint/Extensions/AGENTS.md) | The polyfill-downwards discipline and the ways a polyfill stops being one. Cost: `#if` scattered through spec algorithms, or a downlevel `OrderBy` that spins forever on a comparer JavaScript may legally supply. |\n| touch anything under `Jint/WebApi/` or `Options.WebApi` | [`Jint/WebApi/AGENTS.md`](Jint/WebApi/AGENTS.md) | The four subtree conventions, the whole-file `net8.0` gate, WebIDL's property attributes (enumerable — the opposite of ECMAScript's rule), timer ordering, the diagnostics sink. Cost: a member shipped with the wrong attributes, or a build that breaks only on `net472`. |\n| touch `fetch`, a cookie jar, a redirect hop, or `FetchObserver` | [`Jint/WebApi/Fetch/AGENTS.md`](Jint/WebApi/Fetch/AGENTS.md) | The five settings that make `fetch` a browsing position, per-hop recomputation, the engine-free observer. Cost: a `JsValue` on the transport thread. |\n| write or change a test in the main suite, or read a failure from one of the tests that police this repository | [`Jint.Tests/AGENTS.md`](Jint.Tests/AGENTS.md) | The two assembly attributes six test assemblies share, the rule that a wall-clock number is either the assertion or a wedge ceiling and never both, the helpers that replace xUnit's vocabulary, and the guardian tests no edit to what they check will satisfy. Cost: fixtures that silently share one engine, or a regression hidden by widening a timeout. |\n| touch the vendored web-platform-tests corpus, its shim or its driver | [`Jint.Tests/Wpt/AGENTS.md`](Jint.Tests/Wpt/AGENTS.md) | The exclusion table is the artefact — an entry must match a failing test and no passing one — and a non-zero `NeedsTriage` count means the corpus found a defect somebody still owes the engine a fix for. Cost: five thousand green cases that mean nothing. |\n| run a wpt suite in a real page — the browser lane, its overlay, its wrappers | [`Jint.Tests.Browser/Wpt/AGENTS.md`](Jint.Tests.Browser/Wpt/AGENTS.md) | One corpus and one pin shared with the lane above, upstream's real harness, the results overlay, the five browser-only categories, the census ceiling. Cost: a document that reports nothing counted as a document that passed. |\n| bump the pinned test262 SHA or triage a conformance failure | [`Jint.Tests.Test262/AGENTS.md`](Jint.Tests.Test262/AGENTS.md) | A bump is a code change, not a pin change; and the three exclusion banners, one of which is deliberately not debt. Cost: an upstream normative change landing unread. |\n| write a test proving a third party can reach an API, or read a run that died rather than failed | [`Jint.Tests.PublicInterface/AGENTS.md`](Jint.Tests.PublicInterface/AGENTS.md) | It is the only test project without `InternalsVisibleTo`, which is the whole reason a test there means anything; the table of what counts as a frozen public contract; and what a `TestPipelineException` naming no test actually means. |\n| touch `Jint.DevTools/` — the server, the transport, the protocol pin, the manifest | [`Jint.DevTools/AGENTS.md`](Jint.DevTools/AGENTS.md) | Which thread may touch the engine, the protocol pin and regeneration, the manifest rule. Cost: a command run on the socket thread. |\n| touch a session, a target, the mailbox, or the pause-time message loop | [`Jint.DevTools/Session/AGENTS.md`](Jint.DevTools/Session/AGENTS.md) | How a command crosses to the engine, why a target outlives its engine, what a swap tells each domain, the pause loop. Cost: a domain answering about a document that was replaced. |\n| implement or change a `Jint.DevTools` domain — a command, an event, a handle | [`Jint.DevTools/Domains/AGENTS.md`](Jint.DevTools/Domains/AGENTS.md) | What a client is promised about a value it cannot see, and what may never run script. Cost: a preview that runs a getter. |\n| touch `Jint.HtmlParser/`, parser corpora, generated lookups or its package contracts | [`Jint.HtmlParser/AGENTS.md`](Jint.HtmlParser/AGENTS.md) | Native ownership, inert parsing, defaults and cooperative limits, immutable-read threading, experimental version policy and verification recipes. Cost: Browser work during native parsing, torn reads, or an unverified stable package. |\n| touch the DOM bindings or their generator | [`Jint.Browser/Dom/AGENTS.md`](Jint.Browser/Dom/AGENTS.md) | The explicit binding contract, native adapters, conversion rules, wrapper identity and shape discipline. Cost: a hand-edited `.g.cs`, a stale contract, or an adoption that changes a node's creation brand. |\n| touch anything else under `Jint.Browser/` — the package's principle, an observer, accessibility or extraction, a page budget, what is public | [`Jint.Browser/AGENTS.md`](Jint.Browser/AGENTS.md) | Native parser versus browser ownership, parsing-performance hooks, the LightPanda parity target, generated versus hand-written, observer delivery and public seams. Cost: per-node Browser overhead during parsing, a second DOM store, or a seam published prematurely. |\n| dispatch an event a page can hear, or touch activation, focus, the keyboard or the editor under `Jint.Browser/Events/` | [`Jint.Browser/Events/AGENTS.md`](Jint.Browser/Events/AGENTS.md) | Which algorithm point raises which event, what activation without a layout can be, why the handler content attributes need no notification, and the editor's string and two offsets. Cost: a second event bus, or an event nothing can hear. |\n| touch a page target or a page-level domain under `Jint.Browser/DevTools/` | [`Jint.Browser/DevTools/AGENTS.md`](Jint.Browser/DevTools/AGENTS.md) | A domain reads the target's current runtime per command; the request log the protocol shares with `Page.Requests`. Cost: answering about a replaced document. |\n| touch the accessibility tree or the text/markdown extractors under `Jint.Browser/Accessibility/` or `Extraction/` | [`Jint.Browser/Accessibility/AGENTS.md`](Jint.Browser/Accessibility/AGENTS.md) | html-aam roles and names without layout, what `hidden` means, what a snapshot promises. Cost: a role computed from a box that does not exist. |\n| touch a page — its loop, a navigation, a form, history, storage, a worker, a budget, a box | [`Jint.Browser/Runtime/AGENTS.md`](Jint.Browser/Runtime/AGENTS.md) | The one thread that owns a page's engine and its DOM, why a navigation is a fetch off the loop and a new engine on it, what a turn is, the flat box model. Cost: a second thread in the DOM. |\n| touch the parser driver — how a document, script, module or style sheet loads — or a child frame's window | [`Jint.Browser/Runtime/Parsing/AGENTS.md`](Jint.Browser/Runtime/Parsing/AGENTS.md) | Cooperative native parsing on the page loop, resource pumping, frame realms and scheduling divergences. Cost: script in a native mutation callback, or unrelated tasks inside a parser yield. |\n| touch the `jint-browser` command line, or its tests | [`Jint.Browser.Tool/AGENTS.md`](Jint.Browser.Tool/AGENTS.md) | Why it may never take an `InternalsVisibleTo` grant, the seams that pressure promoted, the exit-code contract, how a tool package is packed. Cost: a seam reached around instead of published. |\n| touch the Model Context Protocol server — a tool, its description, a result | [`Jint.Browser.Mcp/AGENTS.md`](Jint.Browser.Mcp/AGENTS.md) | Why a description is the product, why every tool answers rather than throws, and why stdio is the only transport. Cost: a failure an agent is told nothing about. |\n| write, run, or quote a benchmark number | [`Jint.Benchmark/AGENTS.md`](Jint.Benchmark/AGENTS.md) | The measurement environment and its three modes, the paired comparison, one engine per row. Cost: a `--job short` number in a PR, or a row that depends on its siblings. |\n\nBefore adding to any of them, read [the size budget](#the-size-budget-and-which-agents-load-what) at the end of this file: keep this one under 24 KiB and each of those under 32 KiB, which `dotnet test` fails on rather than merely states.\n\n## Build & Test\n\n```powershell\n# Build (solution, or a single project)\ndotnet build -c Release\ndotnet build -c Release Jint/Jint.csproj\n\n# Run all tests\ndotnet test -c Release\n\n# A specific project (no --timeout: MTP's --timeout bounds the WHOLE run, not one test, and a full\n# Jint.Tests run takes minutes per framework - a 30 s cap ends it early while still printing \"Passed!\")\ndotnet test --project Jint.Tests\\Jint.Tests.csproj -c Release\n# A class or a single test, where a whole-run cap is a sane wedge ceiling\ndotnet test --project Jint.Tests\\Jint.Tests.csproj -c Release --filter \"FullyQualifiedName~Jint.Tests.Runtime.EngineTests\" --timeout 30s\ndotnet test --project Jint.Tests\\Jint.Tests.csproj -c Release --filter \"FullyQualifiedName~Jint.Tests.Runtime.EngineTests.CanAccessCLR\" --timeout 30s\n\n# Test262 conformance suite\ndotnet test -c Release --project Jint.Tests.Test262\\Jint.Tests.Test262.csproj\n```\n\nAlways build and test in **Release** — it is the faster feedback loop and the configuration performance claims are about. Never pass `--no-build`; always work against freshly compiled code. `TreatWarningsAsErrors` is on, so every warning must be fixed. Packages are managed centrally through `Directory.Packages.props`.\n\n`global.json` selects Microsoft Testing Platform v2 for all NUnit test projects.\nUse `--project` for a project path and pass runner options directly, without VSTest's\n`--` separator. Local runner, filtering and parallelism details are in\n[`Jint.Tests/AGENTS.md`](Jint.Tests/AGENTS.md#local-microsoft-testing-platform-runs).\n\nA separate leg runs `Jint.Tests` and `Jint.Tests.PublicInterface` with the host-contract verifiers on\n(`JINT_HOST_CONTRACT_VERIFICATION=1`), the configuration an embedder is told to use. For a quick manual run\nbefore a test exists there is `Jint.Repl`, and **always pass `-t`** so a runaway script cannot hang the\nsession; anything worth keeping becomes a test — in one of eight projects, and the one a change needs is\noften not the one it edits: a conformance failure is never \"fixed\" in `Jint.Tests.Test262`, and a test only\nproves a third party can reach an API in `Jint.Tests.PublicInterface`. What each project holds, the runner\ntimeout each needs, why that verification leg is not the default and the `Jint.Repl` invocations are all in\n[`Jint.Tests/AGENTS.md`](Jint.Tests/AGENTS.md#the-eight-test-projects-and-which-one-a-test-belongs-in).\n\n## Third-party integration surface\n\nJint is not only an engine to work on, it is an engine that gets **embedded**. Integrators host it in-process, project host-supplied objects into script, and bound execution. A significant part of the public API exists only to serve them, and for everything in this section **changing observable behaviour is breaking even when the signature is untouched**. Assume an embedder depends on it before simplifying or \"optimising\" it.\n\nIts rules are split across the files in the index above, and every one of them is in one of those. Four stay here, because they are the ones an agent breaks *before* it knows which file to open — each looks like an ordinary internal refactor right up to the moment an embedder's bounded execution stops being bounded.\n\n### Gotchas\n\nEach of these cost a real integrator or a real bug.\n\n- **Constraints bound one entry into the engine, never a host-driven sequence of them.** Every public entry that runs script — `Execute`, `Evaluate`, `Invoke`, `Engine.Call`, the `JsValue.Call` extension helpers — funnels through `Engine.ExecuteWithConstraints` (`Jint/Engine.cs`), which calls `ResetConstraints()` before the callback and again in its `finally` for any entry that is not nested. So `foreach (var row in rows) predicate.Call(row);` — the single most common embedding shape — hands every element a fresh statement budget, a fresh allocation budget and, worst, a **freshly armed timeout deadline**. Measured: `LimitStatements(100)` does not stop 1000 host `Call`s, `LimitExecutionTime(200ms)` does not fire across 3 s of continuous host-driven execution, and `LimitMemory` never sees more than one call's allocations — while the identical work inside one `Execute` throws in every case. What no embedder expects is that a single function call is a **run**. `Engine.Constraints.Check()` from the host loop does not close the gap either. **What an embedder must do instead — the host-side bound, the in-script loop, and the two in-box constraints that survive the per-entry reset — is [`Jint/Constraints/AGENTS.md`](Jint/Constraints/AGENTS.md#bounding-a-host-driven-sequence), which is also the file to read before changing any of it.**\n- **`DefineOwnPropertyUnchecked` / `DefineOwnDataPropertyUnchecked` always create an *own* property.** They shadow anything of that name on the prototype chain, invoke no inherited setter, and run no `[[DefineOwnProperty]]` validation (so they can never raise `TypeError`) — and storing a raw descriptor under a string key deoptimizes an ordinary hidden-shape receiver, forfeiting its shape inline cache. When to reach for them, and the three cases a shared built-in shape can keep, are in [`Jint/Native/Object/AGENTS.md`](Jint/Native/Object/AGENTS.md#the-unchecked-defines-when-to-reach-for-them).\n- **The enumeration hook is `GetOwnPropertyKeys`, and it is the only one.** `GetOwnProperties` was a second `virtual` whose name read like the hook, and a real integrator overrode only that and shipped an object whose keys were invisible to every script-visible enumeration; since [#3461](https://github.com/sebastienros/jint/pull/3461) it is derived from `GetOwnPropertyKeys` + `GetOwnProperty` and non-virtual, so a host declares its keys once. Which consumers read it, and what a host overrides instead, are in [`Jint/Native/Object/AGENTS.md`](Jint/Native/Object/AGENTS.md#the-enumeration-hook-what-a-host-overrides-instead).\n- **Sharing a `JsValue` across engines is unsupported**, and nothing validates or guards it. An `ObjectInstance` holds a hard reference to its creating engine and realm. Where that *is* written down, and what a fix owes, are in [`Jint/AGENTS.md`](Jint/AGENTS.md#gotchas).\n\nThe rest are in the files indexed above. **Do not add a new gotcha here.** Add it to the file for the area it governs; if none fits, say so in the pull request rather than growing this one.\n\n## Conventions\n\nGlobal usings for Acornima and `Acornima.Ast` are defined in `Directory.Build.props`. Nullable reference types are enabled across the codebase, unsafe code is allowed for performance-critical paths, and the latest analyzers run with `EnforceCodeStyleInBuild`.\n\n### Performance is critical, and the conventions live beside the engine\n\nPerformance is a first-class concern; every change must consider its impact. The checklist that answers it\n— inlining on hot paths, `readonly struct`, `Span<T>` and stack allocation, the `Jint.Pooling` pools,\n`sealed`, `internal`, caching `Prepared<Script>` — sits with the rest of the code patterns (lazy\ninitialization, the `Throw.*` helpers, XML docs, type flags, spec references), the data-structure rule and\nthe internal-first visibility ladder in [`Jint/AGENTS.md`](Jint/AGENTS.md#code-patterns). Two of those bind\nbefore that file is open: cite the spec section a change implements, and default every new member to the\nnarrowest visibility that compiles.\n\n## The size budget, and which agents load what\n\nKeep this file under **24 KiB** and every co-located file under **32 KiB**. Both numbers come from what the\ntools actually do; the per-tool table of which file each agent loads, and the Codex and Devin caps the\nnumbers are taken from, are in [`docs/agent-instruction-files.md`](docs/agent-instruction-files.md).\n\n**When this file is the one that has to shrink, the cut is a trap/remedy split, not a trim.** A gotcha\nstates what an agent breaks before it knows which file to open; the recipe for what to do instead is only\nactionable once that file is open, so it belongs there with a pointer back. That is how the constraints\ngotcha above was split, and it is the first thing to try before anything is shortened or the caps are\ntouched — raising a cap makes Codex's truncation worse, not better.\n\nMost agent ecosystems never reach a co-located file on their own and arrive only because the index names it\n(which of them descend is the last column of that page's table) — which is why the index has a trigger column\nrather than being a list of links, and why anything an agent must obey *before* it knows which area it is in\nhas to stay in this file.\n\n**`Jint.Tests/AgentInstructionFileTests.cs` is what makes those two numbers fail rather than merely be\nstated**, since the truncation is silent and nobody was measuring by hand. What it counts, what else it\nholds together and what its failure hands you are in\n[`docs/agent-instruction-files.md`](docs/agent-instruction-files.md#what-makes-the-budget-fail-rather-than-merely-be-stated).\n"},"files":{".claude/skills/test262-update/SKILL.md":"---\nname: test262-update\ndescription: Bump Jint's pinned tc39/test262 SHA in Jint.Tests.Test262/Test262Harness.settings.json, triage the upstream commit range for normative changes, run the conformance suite, and fix whatever the new tests expose. Use when asked to update/upgrade test262, bump SuiteGitSha, pull in the latest conformance tests, or investigate a test262 conformance failure after a bump.\n---\n\n# Updating the pinned test262 suite\n\nThe visible change is one line — `SuiteGitSha` in `Jint.Tests.Test262/Test262Harness.settings.json`.\nTreat it as a **code** change anyway. Upstream lands tests for normative changes that Jint has not\nimplemented, and those turn green features red. The whole job is triaging the range before you run\nanything, then fixing the engine — never the tests.\n\n## Ground rules\n\n- **Never edit or \"fix\" a test262 test.** If a test is wrong, the answer is an engine fix or, as a last\n  resort, an `ExcludedFiles` entry.\n- **test262 at the pinned SHA outranks the published prose.** See [Normative changes](#3-normative-changes--the-part-that-actually-costs-time).\n- Exclusions outside `intl402/` must be temporary and carry a comment naming what removes them. Today every\n  `ExcludedFiles` entry is intl402 — keep that invariant.\n- A feature that arrives unimplemented parks in `ExcludedFeatures`; the PR that implements it removes the entry.\n- Work in a worktree, not the primary checkout, and start from a fresh `main`.\n\n## 0. Orient\n\n| Thing | Where |\n| --- | --- |\n| The pin | `Jint.Tests.Test262/Test262Harness.settings.json` → `SuiteGitSha` |\n| Local suite checkout (read-only aid) | `../test262` — `origin` = your fork, `upstream` = `tc39/test262` |\n| Generator | `dotnet test262 generate`, from `Jint.Tests.Test262/.config/dotnet-tools.json` |\n| Generated tests | `Jint.Tests.Test262/Generated/` — **gitignored**, so the committed diff stays one line |\n\nThe runner does **not** read `../test262`. `State.Test262StreamLoader` downloads the suite from GitHub at\n`SuiteGitSha`, so the local checkout exists only so you can read the range. Fetch it anyway — you cannot\ntriage without it.\n\nThe `GenerateTestSuite` MSBuild target hashes the settings file and the tool manifest into\n`Generated/.settings.hash`. Change any byte of either and the next build wipes `Generated/` and regenerates.\nSo: never pass `--no-build`, and if you suspect a stale generation, check the hash file rather than guessing.\n\n## 1. Establish the range\n\n```bash\ncd ../test262 && git fetch upstream\ngit log --oneline <pinned-sha>..upstream/main            # or ..<target-sha> if one was given\ngit diff <pinned-sha>..upstream/main -- features.txt\ngit diff --name-only <pinned-sha>..upstream/main | grep -v '^test/'\n```\n\n**Order commits by ancestry, never by author date.** test262 merges rebased branches, so a commit *authored*\nearlier routinely lands on top of one authored later — a real bump had `3655e746` (authored 08-03) sitting\nabove `be13516f` (authored 08-07). Use `--pretty='%h %cd %s'` or `git merge-base --is-ancestor` when the\nordering matters, and confirm the true remote tip with `git ls-remote https://github.com/tc39/test262.git main`.\n\n## 2. Triage every commit\n\nRead the commits, not just the changed-file list.\n\n| Signal | Meaning |\n| --- | --- |\n| only `.github/**`, `tools/**`, `package.json` | infra — zero impact on the run |\n| `features.txt` gained a line | a new feature; if Jint lacks it, it parks in `ExcludedFeatures` with a comment |\n| `src/**.case` / `src/**.template` | procedurally generated tests changed; read the generated output, not the template |\n| new files under `test/built-ins/**` or `test/language/**` | **the risky class** — go to step 3 |\n| a commit message naming a proposal, \"normative\", or an `ecma262#NNNN` | **stop and read the algorithm diff** |\n\nFor a small range, just read the new tests — `git show <sha>:test/path/to/new-test.js`. A test's `info:` block\nusually quotes the numbered algorithm verbatim, which is the fastest way to see what changed and the most\nreliable way to get argument-validation order right.\n\nFor each new behavioural test, check the engine **before** running the suite. `Jint.Repl` turns a 3-minute\nsuite run into a 10-second answer:\n\n```bash\ndotnet run --project Jint.Repl -c Release -- -f scratch.js -t 10   # always pass -t\n```\n\nWrite the assertions as plain `if (…) throw new Error('FAIL …')` — the REPL has no test262 harness. Strip the\n`$DONOTEVALUATE()` / `includes:` lines; for `flags: [async]` tests, assert on `.then(...)` callbacks.\n\n## 3. Normative changes — the part that actually costs time\n\n**The published spec can be behind test262.** A normative PR that reaches consensus gets test262 coverage\nwhile `tc39.es/ecma262` still renders the old algorithm, and an already-merged proposal's own page\n(`tc39.es/proposal-*/`) is frozen at its pre-merge text and will confidently show you the wrong steps. Both\nhappened on the `Promise.try` bump: the proposal page and the living spec agreed with each other and with\nJint, and all three were what the new tests were written to reject.\n\nFind the real change through the repo, not the rendered spec:\n\n```bash\ngh api -X GET search/issues -f q='repo:tc39/ecma262 <feature> <keyword>' \\\n  --jq '.items[] | \"\\(.number) \\(.state) \\(.title)\"'\ngh pr view <n> --repo tc39/ecma262 --json title,state,mergedAt,labels\ngh pr diff <n> --repo tc39/ecma262        # the spec.html algorithm diff is the authority\n```\n\nLabels tell you the status: `has consensus` + `needs implementations` means implement it. `mergedAt: null` is\n**not** a reason to skip — AGENTS.md is explicit that where prose and test262 disagree, test262 at the pinned\nSHA wins.\n\nWhen you implement one:\n\n- Cite the document that owns the feature now. A merged proposal moves to `https://tc39.es/ecma262/#sec-...`;\n  the anchors get renamed on the way in.\n- Add a `<remarks>` naming the normative PR, so the next reader knows why the code and the current published\n  prose disagree.\n- **Re-check the paths the reorder newly reaches.** Moving a step can expose a latent bug that the old\n  ordering made unreachable — see the gotchas below, where hoisting a call above a capability construction\n  turned a dormant `Promise.try()` crash into a live one.\n\n## 4. Bump, build, run\n\n```bash\n# edit SuiteGitSha, then:\ndotnet test -c Release Jint.Tests.Test262/Jint.Tests.Test262.csproj\n```\n\nThe build regenerates before it compiles; no separate generate step. ~3 minutes, ~99.9k tests. No runner\ntimeout needed — the engine defaults to 30 s per test.\n\nVerify the regeneration actually happened rather than trusting a green run over a stale `Generated/`:\n\n```bash\ngrep -c \"<new-test-name>\" Jint.Tests.Test262/Generated/Tests262Harness.Tests.language.generated.cs\n```\n\nA negative parse test appears **twice** per file (strict + sloppy). Deleted upstream tests should be gone.\n\nThen, because a spec fix moves engine behaviour that unit tests pin:\n\n```bash\ndotnet test -c Release Jint.Tests/Jint.Tests.csproj\ndotnet test -c Release Jint.Tests.PublicInterface/Jint.Tests.PublicInterface.csproj\n```\n\n## 5. Fixing what fails\n\nFailure output contains the failing script — strip the line numbers to reproduce it in `Jint.Repl`. Put a\nregression test in `Jint.Tests` for anything test262 does **not** cover (test262 tests the spec, not Jint's\ninternals; a crash on an input no test262 test exercises still needs a pin).\n\n## 6. Decide whether there is a PR at all\n\nIf the suite is green with only the pin moved, there is nothing to ship but a one-line pin bump — say so and\nask before opening a PR. A bump that needs engine fixes is a real PR: pin + fix + regression tests, targeting\n`sebastienros/jint` `main`.\n\n```bash\ngh pr create --repo sebastienros/jint --head <you>:<branch> --base main\n```\n\nKeeping the local suite fork current is a separate, optional courtesy:\n\n```bash\ncd ../test262 && git fetch upstream && git merge --ff-only upstream/main   # then push origin main if wanted\n```\n\n## Gotchas this task has actually hit\n\n- **Author date lies about ordering.** `%ad` is not topology; use `%cd` or `--is-ancestor`.\n- **The proposal page is frozen at merge.** `tc39.es/proposal-promise-try/` still shows the pre-normative\n  algorithm. Never cite it as current for a merged feature.\n- **`spec.html` is too big for a fetch tool.** Asking a fetcher for one section of the living spec returns a\n  truncated prefix and a confident \"not found\". Go through `gh pr diff` instead.\n- **A reorder exposes latent bugs.** `Promise.try` moved `NewPromiseCapability` after the callback call; the\n  argument-slicing that the old ordering never reached with zero arguments then crashed.\n- **`arguments.AsSpan()` is a trap in a built-in.** `ExpressionCache.ArgumentListEvaluation` hands the callee\n  `Unsafe.As<JsValue[]>(object?[])` whenever the argument list is fully cached — *including the zero-argument\n  case* — so `AsSpan()` throws `ArrayTypeMismatchException` (\"Attempted to access an element as a type\n  incompatible with the array\"). Use `arguments.Skip(n)`, which copies element-wise and returns `[]` when\n  there is nothing to take.\n- **`JsValue.Call` on a non-callable throws a CLR `ArgumentException`, not a JS `TypeError`.** Where the spec\n  says `Call(F, V, args)`, write `GetCallable(f).Call(...)` so the failure is a `JavaScriptException` your\n  `Completion` handling can turn into a rejection.\n- **`Promise`-shaped fixes need the abrupt path checked too.** `Completion(...)` wrapping means a throw\n  inside the step becomes a rejection, while a throw from a step *outside* it propagates to the caller. Tests\n  distinguish the two (`ctx-non-ctor.js` expects a synchronous `TypeError`; `throws.js` expects a rejection).\n","AGENTS.md":"# Agent Instructions for Jint\n\nJint is a JavaScript interpreter for .NET. It parses JavaScript using the Acornima library (AST), then interprets it directly — no bytecode generation or DLR usage. The pipeline is `Acornima parser → AST → interpreter → runtime → interop`, each AST node wrapped once in a `Jint*` interpreter class that `Engine` walks; the three stages, those wrapper classes and what they return — `Completion` for a statement, `JsValue` or `Reference` for an expression — are in [`Jint/Runtime/Interpreter/AGENTS.md`](Jint/Runtime/Interpreter/AGENTS.md#the-execution-pipeline).\n\nThis is the canonical instruction file for every agent working on this repository; `CLAUDE.md` imports it. Target and compare work against the **`main`** branch, which is also the PR target.\n\n## How these instructions are laid out\n\nThis file is the entry point and is kept small: it holds what every agent needs before its first edit,\nwhatever that edit turns out to be. Everything else lives in an `AGENTS.md` beside the code it governs.\n**Read the file on the row matching what you are about to do, before you touch that code.**\n\n| If you are about to… | Read first | What is in it, and what a violation costs |\n| --- | --- | --- |\n| change a signature or observable behaviour under `Jint/`, or anything outliving one evaluation — `Prepared<T>`, `Options`, a snapshot, the event loop, an `*Async` entry | [`Jint/AGENTS.md`](Jint/AGENTS.md) | The key runtime types, the namespace map, the engine-source conventions (type co-location, the unsigned-cast bounds check, the code patterns, visibility), and where the frozen-contract table lives. Cost: a silent breaking change for embedders, or one engine's state leaking into another through a shared `Prepared<Script>`. |\n| implement or change an ECMAScript built-in, intrinsic, coercion rule or new syntax | [`Jint/Native/AGENTS.md`](Jint/Native/AGENTS.md) | Which spec document is authoritative, and that test262 beats prose. Cost: implementing a dated snapshot or a compatibility table instead of the living spec — or un-gating a web API that must stay opt-in. |\n| touch `ObjectInstance`, a property descriptor, a property-access lane, or anything a host subclasses | [`Jint/Native/Object/AGENTS.md`](Jint/Native/Object/AGENTS.md), and [`Jint/Runtime/Descriptors/AGENTS.md`](Jint/Runtime/Descriptors/AGENTS.md) for the descriptor itself | The subclassing cliff, `PropertyAccessSemantics`, host-contract verification, `ArrayLikeObject` and the host-object shapes one pointer on, who may reach a new fast lane. Cost: sorting every embedder into a slow path they cannot see or escape. |\n| touch CLR interop — wrappers, converters, reference resolvers, dictionary-backed reads, a host `ProxyHandler`, a CLR exception crossing into script, `[JsAccessible]`, a trimming or AOT annotation | [`Jint/Runtime/Interop/AGENTS.md`](Jint/Runtime/Interop/AGENTS.md), plus [`Jint.AotExample/AGENTS.md`](Jint.AotExample/AGENTS.md) for the native leg | Which host registrations silently disable a compiled lane engine-wide, the immutable-crossing promise, why a generated accessor is a compile-time copy of the run-time compiled one, and which generic instantiations degrade rather than throw. Cost: an engine-wide deoptimisation nobody can see, stale reads, or an `IsAotCompatible` claim nothing runs. |\n| change either Roslyn source generator, or an attribute one of them reads | [`Jint.SourceGenerators/AGENTS.md`](Jint.SourceGenerators/AGENTS.md) | Why there are two analyzer assemblies and only one may ever be packed, the consumer-facing Roslyn pin a bump breaks silently, the value-equality the incremental model rests on, and why accepting a snapshot is the only review the emitted C# gets. Cost: a package whose first build error is in code the consumer never wrote. |\n| add or change a statement/expression handler, a fast path in one, coverage, or anything published onto the AST or a `Prepared<T>` | [`Jint/Runtime/Interpreter/AGENTS.md`](Jint/Runtime/Interpreter/AGENTS.md) | Engine-affine vs shareable state and the AST `UserData` invariant, why coverage counters cannot live on a handler node, and what a warmed call site retains. Cost: a fast path that silently stops being counted, or an engine pinning a host object for its lifetime. |\n| touch module loading, linking, evaluation, or a module's location | [`Jint/Runtime/Modules/AGENTS.md`](Jint/Runtime/Modules/AGENTS.md) | The load phase, which failures become rejections and which must stay fatal, the three host entry points and which one deadlocks, `ModuleFactory.LocationOf`. Cost: a widened `catch` turns a constraint into a rejection that bounds nothing. |\n| touch anything bounding execution — statements, time, memory, recursion, cancellation | [`Jint/Constraints/AGENTS.md`](Jint/Constraints/AGENTS.md) | How limits and CLR access are configured, what disarms the tight-loop lane, what a fan-out brackets, why the cancellation cadence is engine state, how `MaxRecursionDepth` counts, saturated sentinels. Cost: a limit that no longer limits. |\n| write a call site needing an API `net472` / `netstandard2.0` / `netstandard2.1` lacks | [`Jint/Extensions/AGENTS.md`](Jint/Extensions/AGENTS.md) | The polyfill-downwards discipline and the ways a polyfill stops being one. Cost: `#if` scattered through spec algorithms, or a downlevel `OrderBy` that spins forever on a comparer JavaScript may legally supply. |\n| touch anything under `Jint/WebApi/` or `Options.WebApi` | [`Jint/WebApi/AGENTS.md`](Jint/WebApi/AGENTS.md) | The four subtree conventions, the whole-file `net8.0` gate, WebIDL's property attributes (enumerable — the opposite of ECMAScript's rule), timer ordering, the diagnostics sink. Cost: a member shipped with the wrong attributes, or a build that breaks only on `net472`. |\n| touch `fetch`, a cookie jar, a redirect hop, or `FetchObserver` | [`Jint/WebApi/Fetch/AGENTS.md`](Jint/WebApi/Fetch/AGENTS.md) | The five settings that make `fetch` a browsing position, per-hop recomputation, the engine-free observer. Cost: a `JsValue` on the transport thread. |\n| write or change a test in the main suite, or read a failure from one of the tests that police this repository | [`Jint.Tests/AGENTS.md`](Jint.Tests/AGENTS.md) | The two assembly attributes six test assemblies share, the rule that a wall-clock number is either the assertion or a wedge ceiling and never both, the helpers that replace xUnit's vocabulary, and the guardian tests no edit to what they check will satisfy. Cost: fixtures that silently share one engine, or a regression hidden by widening a timeout. |\n| touch the vendored web-platform-tests corpus, its shim or its driver | [`Jint.Tests/Wpt/AGENTS.md`](Jint.Tests/Wpt/AGENTS.md) | The exclusion table is the artefact — an entry must match a failing test and no passing one — and a non-zero `NeedsTriage` count means the corpus found a defect somebody still owes the engine a fix for. Cost: five thousand green cases that mean nothing. |\n| run a wpt suite in a real page — the browser lane, its overlay, its wrappers | [`Jint.Tests.Browser/Wpt/AGENTS.md`](Jint.Tests.Browser/Wpt/AGENTS.md) | One corpus and one pin shared with the lane above, upstream's real harness, the results overlay, the five browser-only categories, the census ceiling. Cost: a document that reports nothing counted as a document that passed. |\n| bump the pinned test262 SHA or triage a conformance failure | [`Jint.Tests.Test262/AGENTS.md`](Jint.Tests.Test262/AGENTS.md) | A bump is a code change, not a pin change; and the three exclusion banners, one of which is deliberately not debt. Cost: an upstream normative change landing unread. |\n| write a test proving a third party can reach an API, or read a run that died rather than failed | [`Jint.Tests.PublicInterface/AGENTS.md`](Jint.Tests.PublicInterface/AGENTS.md) | It is the only test project without `InternalsVisibleTo`, which is the whole reason a test there means anything; the table of what counts as a frozen public contract; and what a `TestPipelineException` naming no test actually means. |\n| touch `Jint.DevTools/` — the server, the transport, the protocol pin, the manifest | [`Jint.DevTools/AGENTS.md`](Jint.DevTools/AGENTS.md) | Which thread may touch the engine, the protocol pin and regeneration, the manifest rule. Cost: a command run on the socket thread. |\n| touch a session, a target, the mailbox, or the pause-time message loop | [`Jint.DevTools/Session/AGENTS.md`](Jint.DevTools/Session/AGENTS.md) | How a command crosses to the engine, why a target outlives its engine, what a swap tells each domain, the pause loop. Cost: a domain answering about a document that was replaced. |\n| implement or change a `Jint.DevTools` domain — a command, an event, a handle | [`Jint.DevTools/Domains/AGENTS.md`](Jint.DevTools/Domains/AGENTS.md) | What a client is promised about a value it cannot see, and what may never run script. Cost: a preview that runs a getter. |\n| touch `Jint.HtmlParser/`, parser corpora, generated lookups or its package contracts | [`Jint.HtmlParser/AGENTS.md`](Jint.HtmlParser/AGENTS.md) | Native ownership, inert parsing, defaults and cooperative limits, immutable-read threading, experimental version policy and verification recipes. Cost: Browser work during native parsing, torn reads, or an unverified stable package. |\n| touch the DOM bindings or their generator | [`Jint.Browser/Dom/AGENTS.md`](Jint.Browser/Dom/AGENTS.md) | The explicit binding contract, native adapters, conversion rules, wrapper identity and shape discipline. Cost: a hand-edited `.g.cs`, a stale contract, or an adoption that changes a node's creation brand. |\n| touch anything else under `Jint.Browser/` — the package's principle, an observer, accessibility or extraction, a page budget, what is public | [`Jint.Browser/AGENTS.md`](Jint.Browser/AGENTS.md) | Native parser versus browser ownership, parsing-performance hooks, the LightPanda parity target, generated versus hand-written, observer delivery and public seams. Cost: per-node Browser overhead during parsing, a second DOM store, or a seam published prematurely. |\n| dispatch an event a page can hear, or touch activation, focus, the keyboard or the editor under `Jint.Browser/Events/` | [`Jint.Browser/Events/AGENTS.md`](Jint.Browser/Events/AGENTS.md) | Which algorithm point raises which event, what activation without a layout can be, why the handler content attributes need no notification, and the editor's string and two offsets. Cost: a second event bus, or an event nothing can hear. |\n| touch a page target or a page-level domain under `Jint.Browser/DevTools/` | [`Jint.Browser/DevTools/AGENTS.md`](Jint.Browser/DevTools/AGENTS.md) | A domain reads the target's current runtime per command; the request log the protocol shares with `Page.Requests`. Cost: answering about a replaced document. |\n| touch the accessibility tree or the text/markdown extractors under `Jint.Browser/Accessibility/` or `Extraction/` | [`Jint.Browser/Accessibility/AGENTS.md`](Jint.Browser/Accessibility/AGENTS.md) | html-aam roles and names without layout, what `hidden` means, what a snapshot promises. Cost: a role computed from a box that does not exist. |\n| touch a page — its loop, a navigation, a form, history, storage, a worker, a budget, a box | [`Jint.Browser/Runtime/AGENTS.md`](Jint.Browser/Runtime/AGENTS.md) | The one thread that owns a page's engine and its DOM, why a navigation is a fetch off the loop and a new engine on it, what a turn is, the flat box model. Cost: a second thread in the DOM. |\n| touch the parser driver — how a document, script, module or style sheet loads — or a child frame's window | [`Jint.Browser/Runtime/Parsing/AGENTS.md`](Jint.Browser/Runtime/Parsing/AGENTS.md) | Cooperative native parsing on the page loop, resource pumping, frame realms and scheduling divergences. Cost: script in a native mutation callback, or unrelated tasks inside a parser yield. |\n| touch the `jint-browser` command line, or its tests | [`Jint.Browser.Tool/AGENTS.md`](Jint.Browser.Tool/AGENTS.md) | Why it may never take an `InternalsVisibleTo` grant, the seams that pressure promoted, the exit-code contract, how a tool package is packed. Cost: a seam reached around instead of published. |\n| touch the Model Context Protocol server — a tool, its description, a result | [`Jint.Browser.Mcp/AGENTS.md`](Jint.Browser.Mcp/AGENTS.md) | Why a description is the product, why every tool answers rather than throws, and why stdio is the only transport. Cost: a failure an agent is told nothing about. |\n| write, run, or quote a benchmark number | [`Jint.Benchmark/AGENTS.md`](Jint.Benchmark/AGENTS.md) | The measurement environment and its three modes, the paired comparison, one engine per row. Cost: a `--job short` number in a PR, or a row that depends on its siblings. |\n\nBefore adding to any of them, read [the size budget](#the-size-budget-and-which-agents-load-what) at the end of this file: keep this one under 24 KiB and each of those under 32 KiB, which `dotnet test` fails on rather than merely states.\n\n## Build & Test\n\n```powershell\n# Build (solution, or a single project)\ndotnet build -c Release\ndotnet build -c Release Jint/Jint.csproj\n\n# Run all tests\ndotnet test -c Release\n\n# A specific project (no --timeout: MTP's --timeout bounds the WHOLE run, not one test, and a full\n# Jint.Tests run takes minutes per framework - a 30 s cap ends it early while still printing \"Passed!\")\ndotnet test --project Jint.Tests\\Jint.Tests.csproj -c Release\n# A class or a single test, where a whole-run cap is a sane wedge ceiling\ndotnet test --project Jint.Tests\\Jint.Tests.csproj -c Release --filter \"FullyQualifiedName~Jint.Tests.Runtime.EngineTests\" --timeout 30s\ndotnet test --project Jint.Tests\\Jint.Tests.csproj -c Release --filter \"FullyQualifiedName~Jint.Tests.Runtime.EngineTests.CanAccessCLR\" --timeout 30s\n\n# Test262 conformance suite\ndotnet test -c Release --project Jint.Tests.Test262\\Jint.Tests.Test262.csproj\n```\n\nAlways build and test in **Release** — it is the faster feedback loop and the configuration performance claims are about. Never pass `--no-build`; always work against freshly compiled code. `TreatWarningsAsErrors` is on, so every warning must be fixed. Packages are managed centrally through `Directory.Packages.props`.\n\n`global.json` selects Microsoft Testing Platform v2 for all NUnit test projects.\nUse `--project` for a project path and pass runner options directly, without VSTest's\n`--` separator. Local runner, filtering and parallelism details are in\n[`Jint.Tests/AGENTS.md`](Jint.Tests/AGENTS.md#local-microsoft-testing-platform-runs).\n\nA separate leg runs `Jint.Tests` and `Jint.Tests.PublicInterface` with the host-contract verifiers on\n(`JINT_HOST_CONTRACT_VERIFICATION=1`), the configuration an embedder is told to use. For a quick manual run\nbefore a test exists there is `Jint.Repl`, and **always pass `-t`** so a runaway script cannot hang the\nsession; anything worth keeping becomes a test — in one of eight projects, and the one a change needs is\noften not the one it edits: a conformance failure is never \"fixed\" in `Jint.Tests.Test262`, and a test only\nproves a third party can reach an API in `Jint.Tests.PublicInterface`. What each project holds, the runner\ntimeout each needs, why that verification leg is not the default and the `Jint.Repl` invocations are all in\n[`Jint.Tests/AGENTS.md`](Jint.Tests/AGENTS.md#the-eight-test-projects-and-which-one-a-test-belongs-in).\n\n## Third-party integration surface\n\nJint is not only an engine to work on, it is an engine that gets **embedded**. Integrators host it in-process, project host-supplied objects into script, and bound execution. A significant part of the public API exists only to serve them, and for everything in this section **changing observable behaviour is breaking even when the signature is untouched**. Assume an embedder depends on it before simplifying or \"optimising\" it.\n\nIts rules are split across the files in the index above, and every one of them is in one of those. Four stay here, because they are the ones an agent breaks *before* it knows which file to open — each looks like an ordinary internal refactor right up to the moment an embedder's bounded execution stops being bounded.\n\n### Gotchas\n\nEach of these cost a real integrator or a real bug.\n\n- **Constraints bound one entry into the engine, never a host-driven sequence of them.** Every public entry that runs script — `Execute`, `Evaluate`, `Invoke`, `Engine.Call`, the `JsValue.Call` extension helpers — funnels through `Engine.ExecuteWithConstraints` (`Jint/Engine.cs`), which calls `ResetConstraints()` before the callback and again in its `finally` for any entry that is not nested. So `foreach (var row in rows) predicate.Call(row);` — the single most common embedding shape — hands every element a fresh statement budget, a fresh allocation budget and, worst, a **freshly armed timeout deadline**. Measured: `LimitStatements(100)` does not stop 1000 host `Call`s, `LimitExecutionTime(200ms)` does not fire across 3 s of continuous host-driven execution, and `LimitMemory` never sees more than one call's allocations — while the identical work inside one `Execute` throws in every case. What no embedder expects is that a single function call is a **run**. `Engine.Constraints.Check()` from the host loop does not close the gap either. **What an embedder must do instead — the host-side bound, the in-script loop, and the two in-box constraints that survive the per-entry reset — is [`Jint/Constraints/AGENTS.md`](Jint/Constraints/AGENTS.md#bounding-a-host-driven-sequence), which is also the file to read before changing any of it.**\n- **`DefineOwnPropertyUnchecked` / `DefineOwnDataPropertyUnchecked` always create an *own* property.** They shadow anything of that name on the prototype chain, invoke no inherited setter, and run no `[[DefineOwnProperty]]` validation (so they can never raise `TypeError`) — and storing a raw descriptor under a string key deoptimizes an ordinary hidden-shape receiver, forfeiting its shape inline cache. When to reach for them, and the three cases a shared built-in shape can keep, are in [`Jint/Native/Object/AGENTS.md`](Jint/Native/Object/AGENTS.md#the-unchecked-defines-when-to-reach-for-them).\n- **The enumeration hook is `GetOwnPropertyKeys`, and it is the only one.** `GetOwnProperties` was a second `virtual` whose name read like the hook, and a real integrator overrode only that and shipped an object whose keys were invisible to every script-visible enumeration; since [#3461](https://github.com/sebastienros/jint/pull/3461) it is derived from `GetOwnPropertyKeys` + `GetOwnProperty` and non-virtual, so a host declares its keys once. Which consumers read it, and what a host overrides instead, are in [`Jint/Native/Object/AGENTS.md`](Jint/Native/Object/AGENTS.md#the-enumeration-hook-what-a-host-overrides-instead).\n- **Sharing a `JsValue` across engines is unsupported**, and nothing validates or guards it. An `ObjectInstance` holds a hard reference to its creating engine and realm. Where that *is* written down, and what a fix owes, are in [`Jint/AGENTS.md`](Jint/AGENTS.md#gotchas).\n\nThe rest are in the files indexed above. **Do not add a new gotcha here.** Add it to the file for the area it governs; if none fits, say so in the pull request rather than growing this one.\n\n## Conventions\n\nGlobal usings for Acornima and `Acornima.Ast` are defined in `Directory.Build.props`. Nullable reference types are enabled across the codebase, unsafe code is allowed for performance-critical paths, and the latest analyzers run with `EnforceCodeStyleInBuild`.\n\n### Performance is critical, and the conventions live beside the engine\n\nPerformance is a first-class concern; every change must consider its impact. The checklist that answers it\n— inlining on hot paths, `readonly struct`, `Span<T>` and stack allocation, the `Jint.Pooling` pools,\n`sealed`, `internal`, caching `Prepared<Script>` — sits with the rest of the code patterns (lazy\ninitialization, the `Throw.*` helpers, XML docs, type flags, spec references), the data-structure rule and\nthe internal-first visibility ladder in [`Jint/AGENTS.md`](Jint/AGENTS.md#code-patterns). Two of those bind\nbefore that file is open: cite the spec section a change implements, and default every new member to the\nnarrowest visibility that compiles.\n\n## The size budget, and which agents load what\n\nKeep this file under **24 KiB** and every co-located file under **32 KiB**. Both numbers come from what the\ntools actually do; the per-tool table of which file each agent loads, and the Codex and Devin caps the\nnumbers are taken from, are in [`docs/agent-instruction-files.md`](docs/agent-instruction-files.md).\n\n**When this file is the one that has to shrink, the cut is a trap/remedy split, not a trim.** A gotcha\nstates what an agent breaks before it knows which file to open; the recipe for what to do instead is only\nactionable once that file is open, so it belongs there with a pointer back. That is how the constraints\ngotcha above was split, and it is the first thing to try before anything is shortened or the caps are\ntouched — raising a cap makes Codex's truncation worse, not better.\n\nMost agent ecosystems never reach a co-located file on their own and arrive only because the index names it\n(which of them descend is the last column of that page's table) — which is why the index has a trigger column\nrather than being a list of links, and why anything an agent must obey *before* it knows which area it is in\nhas to stay in this file.\n\n**`Jint.Tests/AgentInstructionFileTests.cs` is what makes those two numbers fail rather than merely be\nstated**, since the truncation is silent and nobody was measuring by hand. What it counts, what else it\nholds together and what its failure hands you are in\n[`docs/agent-instruction-files.md`](docs/agent-instruction-files.md#what-makes-the-budget-fail-rather-than-merely-be-stated).\n"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","rawUrl":"https://raw.githubusercontent.com/sebastienros/jint/HEAD/AGENTS.md","title":"AI Agent Protocol & Instructions","category":"root-instruction","format":"markdown","content":"# Agent Instructions for Jint\n\nJint is a JavaScript interpreter for .NET. It parses JavaScript using the Acornima library (AST), then interprets it directly — no bytecode generation or DLR usage. The pipeline is `Acornima parser → AST → interpreter → runtime → interop`, each AST node wrapped once in a `Jint*` interpreter class that `Engine` walks; the three stages, those wrapper classes and what they return — `Completion` for a statement, `JsValue` or `Reference` for an expression — are in [`Jint/Runtime/Interpreter/AGENTS.md`](Jint/Runtime/Interpreter/AGENTS.md#the-execution-pipeline).\n\nThis is the canonical instruction file for every agent working on this repository; `CLAUDE.md` imports it. Target and compare work against the **`main`** branch, which is also the PR target.\n\n## How these instructions are laid out\n\nThis file is the entry point and is kept small: it holds what every agent needs before its first edit,\nwhatever that edit turns out to be. Everything else lives in an `AGENTS.md` beside the code it governs.\n**Read the file on the row matching what you are about to do, before you touch that code.**\n\n| If you are about to… | Read first | What is in it, and what a violation costs |\n| --- | --- | --- |\n| change a signature or observable behaviour under `Jint/`, or anything outliving one evaluation — `Prepared<T>`, `Options`, a snapshot, the event loop, an `*Async` entry | [`Jint/AGENTS.md`](Jint/AGENTS.md) | The key runtime types, the namespace map, the engine-source conventions (type co-location, the unsigned-cast bounds check, the code patterns, visibility), and where the frozen-contract table lives. Cost: a silent breaking change for embedders, or one engine's state leaking into another through a shared `Prepared<Script>`. |\n| implement or change an ECMAScript built-in, intrinsic, coercion rule or new syntax | [`Jint/Native/AGENTS.md`](Jint/Native/AGENTS.md) | Which spec document is authoritative, and that test262 beats prose. Cost: implementing a dated snapshot or a compatibility table instead of the living spec — or un-gating a web API that must stay opt-in. |\n| touch `ObjectInstance`, a property descriptor, a property-access lane, or anything a host subclasses | [`Jint/Native/Object/AGENTS.md`](Jint/Native/Object/AGENTS.md), and [`Jint/Runtime/Descriptors/AGENTS.md`](Jint/Runtime/Descriptors/AGENTS.md) for the descriptor itself | The subclassing cliff, `PropertyAccessSemantics`, host-contract verification, `ArrayLikeObject` and the host-object shapes one pointer on, who may reach a new fast lane. Cost: sorting every embedder into a slow path they cannot see or escape. |\n| touch CLR interop — wrappers, converters, reference resolvers, dictionary-backed reads, a host `ProxyHandler`, a CLR exception crossing into script, `[JsAccessible]`, a trimming or AOT annotation | [`Jint/Runtime/Interop/AGENTS.md`](Jint/Runtime/Interop/AGENTS.md), plus [`Jint.AotExample/AGENTS.md`](Jint.AotExample/AGENTS.md) for the native leg | Which host registrations silently disable a compiled lane engine-wide, the immutable-crossing promise, why a generated accessor is a compile-time copy of the run-time compiled one, and which generic instantiations degrade rather than throw. Cost: an engine-wide deoptimisation nobody can see, stale reads, or an `IsAotCompatible` claim nothing runs. |\n| change either Roslyn source generator, or an attribute one of them reads | [`Jint.SourceGenerators/AGENTS.md`](Jint.SourceGenerators/AGENTS.md) | Why there are two analyzer assemblies and only one may ever be packed, the consumer-facing Roslyn pin a bump breaks silently, the value-equality the incremental model rests on, and why accepting a snapshot is the only review the emitted C# gets. Cost: a package whose first build error is in code the consumer never wrote. |\n| add or change a statement/expression handler, a fast path in one, coverage, or anything published onto the AST or a `Prepared<T>` | [`Jint/Runtime/Interpreter/AGENTS.md`](Jint/Runtime/Interpreter/AGENTS.md) | Engine-affine vs shareable state and the AST `UserData` invariant, why coverage counters cannot live on a handler node, and what a warmed call site retains. Cost: a fast path that silently stops being counted, or an engine pinning a host object for its lifetime. |\n| touch module loading, linking, evaluation, or a module's location | [`Jint/Runtime/Modules/AGENTS.md`](Jint/Runtime/Modules/AGENTS.md) | The load phase, which failures become rejections and which must stay fatal, the three host entry points and which one deadlocks, `ModuleFactory.LocationOf`. Cost: a widened `catch` turns a constraint into a rejection that bounds nothing. |\n| touch anything bounding execution — statements, time, memory, recursion, cancellation | [`Jint/Constraints/AGENTS.md`](Jint/Constraints/AGENTS.md) | How limits and CLR access are configured, what disarms the tight-loop lane, what a fan-out brackets, why the cancellation cadence is engine state, how `MaxRecursionDepth` counts, saturated sentinels. Cost: a limit that no longer limits. |\n| write a call site needing an API `net472` / `netstandard2.0` / `netstandard2.1` lacks | [`Jint/Extensions/AGENTS.md`](Jint/Extensions/AGENTS.md) | The polyfill-downwards discipline and the ways a polyfill stops being one. Cost: `#if` scattered through spec algorithms, or a downlevel `OrderBy` that spins forever on a comparer JavaScript may legally supply. |\n| touch anything under `Jint/WebApi/` or `Options.WebApi` | [`Jint/WebApi/AGENTS.md`](Jint/WebApi/AGENTS.md) | The four subtree conventions, the whole-file `net8.0` gate, WebIDL's property attributes (enumerable — the opposite of ECMAScript's rule), timer ordering, the diagnostics sink. Cost: a member shipped with the wrong attributes, or a build that breaks only on `net472`. |\n| touch `fetch`, a cookie jar, a redirect hop, or `FetchObserver` | [`Jint/WebApi/Fetch/AGENTS.md`](Jint/WebApi/Fetch/AGENTS.md) | The five settings that make `fetch` a browsing position, per-hop recomputation, the engine-free observer. Cost: a `JsValue` on the transport thread. |\n| write or change a test in the main suite, or read a failure from one of the tests that police this repository | [`Jint.Tests/AGENTS.md`](Jint.Tests/AGENTS.md) | The two assembly attributes six test assemblies share, the rule that a wall-clock number is either the assertion or a wedge ceiling and never both, the helpers that replace xUnit's vocabulary, and the guardian tests no edit to what they check will satisfy. Cost: fixtures that silently share one engine, or a regression hidden by widening a timeout. |\n| touch the vendored web-platform-tests corpus, its shim or its driver | [`Jint.Tests/Wpt/AGENTS.md`](Jint.Tests/Wpt/AGENTS.md) | The exclusion table is the artefact — an entry must match a failing test and no passing one — and a non-zero `NeedsTriage` count means the corpus found a defect somebody still owes the engine a fix for. Cost: five thousand green cases that mean nothing. |\n| run a wpt suite in a real page — the browser lane, its overlay, its wrappers | [`Jint.Tests.Browser/Wpt/AGENTS.md`](Jint.Tests.Browser/Wpt/AGENTS.md) | One corpus and one pin shared with the lane above, upstream's real harness, the results overlay, the five browser-only categories, the census ceiling. Cost: a document that reports nothing counted as a document that passed. |\n| bump the pinned test262 SHA or triage a conformance failure | [`Jint.Tests.Test262/AGENTS.md`](Jint.Tests.Test262/AGENTS.md) | A bump is a code change, not a pin change; and the three exclusion banners, one of which is deliberately not debt. Cost: an upstream normative change landing unread. |\n| write a test proving a third party can reach an API, or read a run that died rather than failed | [`Jint.Tests.PublicInterface/AGENTS.md`](Jint.Tests.PublicInterface/AGENTS.md) | It is the only test project without `InternalsVisibleTo`, which is the whole reason a test there means anything; the table of what counts as a frozen public contract; and what a `TestPipelineException` naming no test actually means. |\n| touch `Jint.DevTools/` — the server, the transport, the protocol pin, the manifest | [`Jint.DevTools/AGENTS.md`](Jint.DevTools/AGENTS.md) | Which thread may touch the engine, the protocol pin and regeneration, the manifest rule. Cost: a command run on the socket thread. |\n| touch a session, a target, the mailbox, or the pause-time message loop | [`Jint.DevTools/Session/AGENTS.md`](Jint.DevTools/Session/AGENTS.md) | How a command crosses to the engine, why a target outlives its engine, what a swap tells each domain, the pause loop. Cost: a domain answering about a document that was replaced. |\n| implement or change a `Jint.DevTools` domain — a command, an event, a handle | [`Jint.DevTools/Domains/AGENTS.md`](Jint.DevTools/Domains/AGENTS.md) | What a client is promised about a value it cannot see, and what may never run script. Cost: a preview that runs a getter. |\n| touch `Jint.HtmlParser/`, parser corpora, generated lookups or its package contracts | [`Jint.HtmlParser/AGENTS.md`](Jint.HtmlParser/AGENTS.md) | Native ownership, inert parsing, defaults and cooperative limits, immutable-read threading, experimental version policy and verification recipes. Cost: Browser work during native parsing, torn reads, or an unverified stable package. |\n| touch the DOM bindings or their generator | [`Jint.Browser/Dom/AGENTS.md`](Jint.Browser/Dom/AGENTS.md) | The explicit binding contract, native adapters, conversion rules, wrapper identity and shape discipline. Cost: a hand-edited `.g.cs`, a stale contract, or an adoption that changes a node's creation brand. |\n| touch anything else under `Jint.Browser/` — the package's principle, an observer, accessibility or extraction, a page budget, what is public | [`Jint.Browser/AGENTS.md`](Jint.Browser/AGENTS.md) | Native parser versus browser ownership, parsing-performance hooks, the LightPanda parity target, generated versus hand-written, observer delivery and public seams. Cost: per-node Browser overhead during parsing, a second DOM store, or a seam published prematurely. |\n| dispatch an event a page can hear, or touch activation, focus, the keyboard or the editor under `Jint.Browser/Events/` | [`Jint.Browser/Events/AGENTS.md`](Jint.Browser/Events/AGENTS.md) | Which algorithm point raises which event, what activation without a layout can be, why the handler content attributes need no notification, and the editor's string and two offsets. Cost: a second event bus, or an event nothing can hear. |\n| touch a page target or a page-level domain under `Jint.Browser/DevTools/` | [`Jint.Browser/DevTools/AGENTS.md`](Jint.Browser/DevTools/AGENTS.md) | A domain reads the target's current runtime per command; the request log the protocol shares with `Page.Requests`. Cost: answering about a replaced document. |\n| touch the accessibility tree or the text/markdown extractors under `Jint.Browser/Accessibility/` or `Extraction/` | [`Jint.Browser/Accessibility/AGENTS.md`](Jint.Browser/Accessibility/AGENTS.md) | html-aam roles and names without layout, what `hidden` means, what a snapshot promises. Cost: a role computed from a box that does not exist. |\n| touch a page — its loop, a navigation, a form, history, storage, a worker, a budget, a box | [`Jint.Browser/Runtime/AGENTS.md`](Jint.Browser/Runtime/AGENTS.md) | The one thread that owns a page's engine and its DOM, why a navigation is a fetch off the loop and a new engine on it, what a turn is, the flat box model. Cost: a second thread in the DOM. |\n| touch the parser driver — how a document, script, module or style sheet loads — or a child frame's window | [`Jint.Browser/Runtime/Parsing/AGENTS.md`](Jint.Browser/Runtime/Parsing/AGENTS.md) | Cooperative native parsing on the page loop, resource pumping, frame realms and scheduling divergences. Cost: script in a native mutation callback, or unrelated tasks inside a parser yield. |\n| touch the `jint-browser` command line, or its tests | [`Jint.Browser.Tool/AGENTS.md`](Jint.Browser.Tool/AGENTS.md) | Why it may never take an `InternalsVisibleTo` grant, the seams that pressure promoted, the exit-code contract, how a tool package is packed. Cost: a seam reached around instead of published. |\n| touch the Model Context Protocol server — a tool, its description, a result | [`Jint.Browser.Mcp/AGENTS.md`](Jint.Browser.Mcp/AGENTS.md) | Why a description is the product, why every tool answers rather than throws, and why stdio is the only transport. Cost: a failure an agent is told nothing about. |\n| write, run, or quote a benchmark number | [`Jint.Benchmark/AGENTS.md`](Jint.Benchmark/AGENTS.md) | The measurement environment and its three modes, the paired comparison, one engine per row. Cost: a `--job short` number in a PR, or a row that depends on its siblings. |\n\nBefore adding to any of them, read [the size budget](#the-size-budget-and-which-agents-load-what) at the end of this file: keep this one under 24 KiB and each of those under 32 KiB, which `dotnet test` fails on rather than merely states.\n\n## Build & Test\n\n```powershell\n# Build (solution, or a single project)\ndotnet build -c Release\ndotnet build -c Release Jint/Jint.csproj\n\n# Run all tests\ndotnet test -c Release\n\n# A specific project (no --timeout: MTP's --timeout bounds the WHOLE run, not one test, and a full\n# Jint.Tests run takes minutes per framework - a 30 s cap ends it early while still printing \"Passed!\")\ndotnet test --project Jint.Tests\\Jint.Tests.csproj -c Release\n# A class or a single test, where a whole-run cap is a sane wedge ceiling\ndotnet test --project Jint.Tests\\Jint.Tests.csproj -c Release --filter \"FullyQualifiedName~Jint.Tests.Runtime.EngineTests\" --timeout 30s\ndotnet test --project Jint.Tests\\Jint.Tests.csproj -c Release --filter \"FullyQualifiedName~Jint.Tests.Runtime.EngineTests.CanAccessCLR\" --timeout 30s\n\n# Test262 conformance suite\ndotnet test -c Release --project Jint.Tests.Test262\\Jint.Tests.Test262.csproj\n```\n\nAlways build and test in **Release** — it is the faster feedback loop and the configuration performance claims are about. Never pass `--no-build`; always work against freshly compiled code. `TreatWarningsAsErrors` is on, so every warning must be fixed. Packages are managed centrally through `Directory.Packages.props`.\n\n`global.json` selects Microsoft Testing Platform v2 for all NUnit test projects.\nUse `--project` for a project path and pass runner options directly, without VSTest's\n`--` separator. Local runner, filtering and parallelism details are in\n[`Jint.Tests/AGENTS.md`](Jint.Tests/AGENTS.md#local-microsoft-testing-platform-runs).\n\nA separate leg runs `Jint.Tests` and `Jint.Tests.PublicInterface` with the host-contract verifiers on\n(`JINT_HOST_CONTRACT_VERIFICATION=1`), the configuration an embedder is told to use. For a quick manual run\nbefore a test exists there is `Jint.Repl`, and **always pass `-t`** so a runaway script cannot hang the\nsession; anything worth keeping becomes a test — in one of eight projects, and the one a change needs is\noften not the one it edits: a conformance failure is never \"fixed\" in `Jint.Tests.Test262`, and a test only\nproves a third party can reach an API in `Jint.Tests.PublicInterface`. What each project holds, the runner\ntimeout each needs, why that verification leg is not the default and the `Jint.Repl` invocations are all in\n[`Jint.Tests/AGENTS.md`](Jint.Tests/AGENTS.md#the-eight-test-projects-and-which-one-a-test-belongs-in).\n\n## Third-party integration surface\n\nJint is not only an engine to work on, it is an engine that gets **embedded**. Integrators host it in-process, project host-supplied objects into script, and bound execution. A significant part of the public API exists only to serve them, and for everything in this section **changing observable behaviour is breaking even when the signature is untouched**. Assume an embedder depends on it before simplifying or \"optimising\" it.\n\nIts rules are split across the files in the index above, and every one of them is in one of those. Four stay here, because they are the ones an agent breaks *before* it knows which file to open — each looks like an ordinary internal refactor right up to the moment an embedder's bounded execution stops being bounded.\n\n### Gotchas\n\nEach of these cost a real integrator or a real bug.\n\n- **Constraints bound one entry into the engine, never a host-driven sequence of them.** Every public entry that runs script — `Execute`, `Evaluate`, `Invoke`, `Engine.Call`, the `JsValue.Call` extension helpers — funnels through `Engine.ExecuteWithConstraints` (`Jint/Engine.cs`), which calls `ResetConstraints()` before the callback and again in its `finally` for any entry that is not nested. So `foreach (var row in rows) predicate.Call(row);` — the single most common embedding shape — hands every element a fresh statement budget, a fresh allocation budget and, worst, a **freshly armed timeout deadline**. Measured: `LimitStatements(100)` does not stop 1000 host `Call`s, `LimitExecutionTime(200ms)` does not fire across 3 s of continuous host-driven execution, and `LimitMemory` never sees more than one call's allocations — while the identical work inside one `Execute` throws in every case. What no embedder expects is that a single function call is a **run**. `Engine.Constraints.Check()` from the host loop does not close the gap either. **What an embedder must do instead — the host-side bound, the in-script loop, and the two in-box constraints that survive the per-entry reset — is [`Jint/Constraints/AGENTS.md`](Jint/Constraints/AGENTS.md#bounding-a-host-driven-sequence), which is also the file to read before changing any of it.**\n- **`DefineOwnPropertyUnchecked` / `DefineOwnDataPropertyUnchecked` always create an *own* property.** They shadow anything of that name on the prototype chain, invoke no inherited setter, and run no `[[DefineOwnProperty]]` validation (so they can never raise `TypeError`) — and storing a raw descriptor under a string key deoptimizes an ordinary hidden-shape receiver, forfeiting its shape inline cache. When to reach for them, and the three cases a shared built-in shape can keep, are in [`Jint/Native/Object/AGENTS.md`](Jint/Native/Object/AGENTS.md#the-unchecked-defines-when-to-reach-for-them).\n- **The enumeration hook is `GetOwnPropertyKeys`, and it is the only one.** `GetOwnProperties` was a second `virtual` whose name read like the hook, and a real integrator overrode only that and shipped an object whose keys were invisible to every script-visible enumeration; since [#3461](https://github.com/sebastienros/jint/pull/3461) it is derived from `GetOwnPropertyKeys` + `GetOwnProperty` and non-virtual, so a host declares its keys once. Which consumers read it, and what a host overrides instead, are in [`Jint/Native/Object/AGENTS.md`](Jint/Native/Object/AGENTS.md#the-enumeration-hook-what-a-host-overrides-instead).\n- **Sharing a `JsValue` across engines is unsupported**, and nothing validates or guards it. An `ObjectInstance` holds a hard reference to its creating engine and realm. Where that *is* written down, and what a fix owes, are in [`Jint/AGENTS.md`](Jint/AGENTS.md#gotchas).\n\nThe rest are in the files indexed above. **Do not add a new gotcha here.** Add it to the file for the area it governs; if none fits, say so in the pull request rather than growing this one.\n\n## Conventions\n\nGlobal usings for Acornima and `Acornima.Ast` are defined in `Directory.Build.props`. Nullable reference types are enabled across the codebase, unsafe code is allowed for performance-critical paths, and the latest analyzers run with `EnforceCodeStyleInBuild`.\n\n### Performance is critical, and the conventions live beside the engine\n\nPerformance is a first-class concern; every change must consider its impact. The checklist that answers it\n— inlining on hot paths, `readonly struct`, `Span<T>` and stack allocation, the `Jint.Pooling` pools,\n`sealed`, `internal`, caching `Prepared<Script>` — sits with the rest of the code patterns (lazy\ninitialization, the `Throw.*` helpers, XML docs, type flags, spec references), the data-structure rule and\nthe internal-first visibility ladder in [`Jint/AGENTS.md`](Jint/AGENTS.md#code-patterns). Two of those bind\nbefore that file is open: cite the spec section a change implements, and default every new member to the\nnarrowest visibility that compiles.\n\n## The size budget, and which agents load what\n\nKeep this file under **24 KiB** and every co-located file under **32 KiB**. Both numbers come from what the\ntools actually do; the per-tool table of which file each agent loads, and the Codex and Devin caps the\nnumbers are taken from, are in [`docs/agent-instruction-files.md`](docs/agent-instruction-files.md).\n\n**When this file is the one that has to shrink, the cut is a trap/remedy split, not a trim.** A gotcha\nstates what an agent breaks before it knows which file to open; the recipe for what to do instead is only\nactionable once that file is open, so it belongs there with a pointer back. That is how the constraints\ngotcha above was split, and it is the first thing to try before anything is shortened or the caps are\ntouched — raising a cap makes Codex's truncation worse, not better.\n\nMost agent ecosystems never reach a co-located file on their own and arrive only because the index names it\n(which of them descend is the last column of that page's table) — which is why the index has a trigger column\nrather than being a list of links, and why anything an agent must obey *before* it knows which area it is in\nhas to stay in this file.\n\n**`Jint.Tests/AgentInstructionFileTests.cs` is what makes those two numbers fail rather than merely be\nstated**, since the truncation is silent and nobody was measuring by hand. What it counts, what else it\nholds together and what its failure hands you are in\n[`docs/agent-instruction-files.md`](docs/agent-instruction-files.md#what-makes-the-budget-fail-rather-than-merely-be-stated).\n","isInternal":false,"tokens":5287,"sizeBytes":22037},{"name":"SKILL.md","path":".claude/skills/test262-update/SKILL.md","rawUrl":"https://raw.githubusercontent.com/sebastienros/jint/HEAD/.claude/skills/test262-update/SKILL.md","title":"test262-update","category":"anthropic-skill","format":"markdown","content":"---\nname: test262-update\ndescription: Bump Jint's pinned tc39/test262 SHA in Jint.Tests.Test262/Test262Harness.settings.json, triage the upstream commit range for normative changes, run the conformance suite, and fix whatever the new tests expose. Use when asked to update/upgrade test262, bump SuiteGitSha, pull in the latest conformance tests, or investigate a test262 conformance failure after a bump.\n---\n\n# Updating the pinned test262 suite\n\nThe visible change is one line — `SuiteGitSha` in `Jint.Tests.Test262/Test262Harness.settings.json`.\nTreat it as a **code** change anyway. Upstream lands tests for normative changes that Jint has not\nimplemented, and those turn green features red. The whole job is triaging the range before you run\nanything, then fixing the engine — never the tests.\n\n## Ground rules\n\n- **Never edit or \"fix\" a test262 test.** If a test is wrong, the answer is an engine fix or, as a last\n  resort, an `ExcludedFiles` entry.\n- **test262 at the pinned SHA outranks the published prose.** See [Normative changes](#3-normative-changes--the-part-that-actually-costs-time).\n- Exclusions outside `intl402/` must be temporary and carry a comment naming what removes them. Today every\n  `ExcludedFiles` entry is intl402 — keep that invariant.\n- A feature that arrives unimplemented parks in `ExcludedFeatures`; the PR that implements it removes the entry.\n- Work in a worktree, not the primary checkout, and start from a fresh `main`.\n\n## 0. Orient\n\n| Thing | Where |\n| --- | --- |\n| The pin | `Jint.Tests.Test262/Test262Harness.settings.json` → `SuiteGitSha` |\n| Local suite checkout (read-only aid) | `../test262` — `origin` = your fork, `upstream` = `tc39/test262` |\n| Generator | `dotnet test262 generate`, from `Jint.Tests.Test262/.config/dotnet-tools.json` |\n| Generated tests | `Jint.Tests.Test262/Generated/` — **gitignored**, so the committed diff stays one line |\n\nThe runner does **not** read `../test262`. `State.Test262StreamLoader` downloads the suite from GitHub at\n`SuiteGitSha`, so the local checkout exists only so you can read the range. Fetch it anyway — you cannot\ntriage without it.\n\nThe `GenerateTestSuite` MSBuild target hashes the settings file and the tool manifest into\n`Generated/.settings.hash`. Change any byte of either and the next build wipes `Generated/` and regenerates.\nSo: never pass `--no-build`, and if you suspect a stale generation, check the hash file rather than guessing.\n\n## 1. Establish the range\n\n```bash\ncd ../test262 && git fetch upstream\ngit log --oneline <pinned-sha>..upstream/main            # or ..<target-sha> if one was given\ngit diff <pinned-sha>..upstream/main -- features.txt\ngit diff --name-only <pinned-sha>..upstream/main | grep -v '^test/'\n```\n\n**Order commits by ancestry, never by author date.** test262 merges rebased branches, so a commit *authored*\nearlier routinely lands on top of one authored later — a real bump had `3655e746` (authored 08-03) sitting\nabove `be13516f` (authored 08-07). Use `--pretty='%h %cd %s'` or `git merge-base --is-ancestor` when the\nordering matters, and confirm the true remote tip with `git ls-remote https://github.com/tc39/test262.git main`.\n\n## 2. Triage every commit\n\nRead the commits, not just the changed-file list.\n\n| Signal | Meaning |\n| --- | --- |\n| only `.github/**`, `tools/**`, `package.json` | infra — zero impact on the run |\n| `features.txt` gained a line | a new feature; if Jint lacks it, it parks in `ExcludedFeatures` with a comment |\n| `src/**.case` / `src/**.template` | procedurally generated tests changed; read the generated output, not the template |\n| new files under `test/built-ins/**` or `test/language/**` | **the risky class** — go to step 3 |\n| a commit message naming a proposal, \"normative\", or an `ecma262#NNNN` | **stop and read the algorithm diff** |\n\nFor a small range, just read the new tests — `git show <sha>:test/path/to/new-test.js`. A test's `info:` block\nusually quotes the numbered algorithm verbatim, which is the fastest way to see what changed and the most\nreliable way to get argument-validation order right.\n\nFor each new behavioural test, check the engine **before** running the suite. `Jint.Repl` turns a 3-minute\nsuite run into a 10-second answer:\n\n```bash\ndotnet run --project Jint.Repl -c Release -- -f scratch.js -t 10   # always pass -t\n```\n\nWrite the assertions as plain `if (…) throw new Error('FAIL …')` — the REPL has no test262 harness. Strip the\n`$DONOTEVALUATE()` / `includes:` lines; for `flags: [async]` tests, assert on `.then(...)` callbacks.\n\n## 3. Normative changes — the part that actually costs time\n\n**The published spec can be behind test262.** A normative PR that reaches consensus gets test262 coverage\nwhile `tc39.es/ecma262` still renders the old algorithm, and an already-merged proposal's own page\n(`tc39.es/proposal-*/`) is frozen at its pre-merge text and will confidently show you the wrong steps. Both\nhappened on the `Promise.try` bump: the proposal page and the living spec agreed with each other and with\nJint, and all three were what the new tests were written to reject.\n\nFind the real change through the repo, not the rendered spec:\n\n```bash\ngh api -X GET search/issues -f q='repo:tc39/ecma262 <feature> <keyword>' \\\n  --jq '.items[] | \"\\(.number) \\(.state) \\(.title)\"'\ngh pr view <n> --repo tc39/ecma262 --json title,state,mergedAt,labels\ngh pr diff <n> --repo tc39/ecma262        # the spec.html algorithm diff is the authority\n```\n\nLabels tell you the status: `has consensus` + `needs implementations` means implement it. `mergedAt: null` is\n**not** a reason to skip — AGENTS.md is explicit that where prose and test262 disagree, test262 at the pinned\nSHA wins.\n\nWhen you implement one:\n\n- Cite the document that owns the feature now. A merged proposal moves to `https://tc39.es/ecma262/#sec-...`;\n  the anchors get renamed on the way in.\n- Add a `<remarks>` naming the normative PR, so the next reader knows why the code and the current published\n  prose disagree.\n- **Re-check the paths the reorder newly reaches.** Moving a step can expose a latent bug that the old\n  ordering made unreachable — see the gotchas below, where hoisting a call above a capability construction\n  turned a dormant `Promise.try()` crash into a live one.\n\n## 4. Bump, build, run\n\n```bash\n# edit SuiteGitSha, then:\ndotnet test -c Release Jint.Tests.Test262/Jint.Tests.Test262.csproj\n```\n\nThe build regenerates before it compiles; no separate generate step. ~3 minutes, ~99.9k tests. No runner\ntimeout needed — the engine defaults to 30 s per test.\n\nVerify the regeneration actually happened rather than trusting a green run over a stale `Generated/`:\n\n```bash\ngrep -c \"<new-test-name>\" Jint.Tests.Test262/Generated/Tests262Harness.Tests.language.generated.cs\n```\n\nA negative parse test appears **twice** per file (strict + sloppy). Deleted upstream tests should be gone.\n\nThen, because a spec fix moves engine behaviour that unit tests pin:\n\n```bash\ndotnet test -c Release Jint.Tests/Jint.Tests.csproj\ndotnet test -c Release Jint.Tests.PublicInterface/Jint.Tests.PublicInterface.csproj\n```\n\n## 5. Fixing what fails\n\nFailure output contains the failing script — strip the line numbers to reproduce it in `Jint.Repl`. Put a\nregression test in `Jint.Tests` for anything test262 does **not** cover (test262 tests the spec, not Jint's\ninternals; a crash on an input no test262 test exercises still needs a pin).\n\n## 6. Decide whether there is a PR at all\n\nIf the suite is green with only the pin moved, there is nothing to ship but a one-line pin bump — say so and\nask before opening a PR. A bump that needs engine fixes is a real PR: pin + fix + regression tests, targeting\n`sebastienros/jint` `main`.\n\n```bash\ngh pr create --repo sebastienros/jint --head <you>:<branch> --base main\n```\n\nKeeping the local suite fork current is a separate, optional courtesy:\n\n```bash\ncd ../test262 && git fetch upstream && git merge --ff-only upstream/main   # then push origin main if wanted\n```\n\n## Gotchas this task has actually hit\n\n- **Author date lies about ordering.** `%ad` is not topology; use `%cd` or `--is-ancestor`.\n- **The proposal page is frozen at merge.** `tc39.es/proposal-promise-try/` still shows the pre-normative\n  algorithm. Never cite it as current for a merged feature.\n- **`spec.html` is too big for a fetch tool.** Asking a fetcher for one section of the living spec returns a\n  truncated prefix and a confident \"not found\". Go through `gh pr diff` instead.\n- **A reorder exposes latent bugs.** `Promise.try` moved `NewPromiseCapability` after the callback call; the\n  argument-slicing that the old ordering never reached with zero arguments then crashed.\n- **`arguments.AsSpan()` is a trap in a built-in.** `ExpressionCache.ArgumentListEvaluation` hands the callee\n  `Unsafe.As<JsValue[]>(object?[])` whenever the argument list is fully cached — *including the zero-argument\n  case* — so `AsSpan()` throws `ArrayTypeMismatchException` (\"Attempted to access an element as a type\n  incompatible with the array\"). Use `arguments.Skip(n)`, which copies element-wise and returns `[]` when\n  there is nothing to take.\n- **`JsValue.Call` on a non-callable throws a CLR `ArgumentException`, not a JS `TypeError`.** Where the spec\n  says `Call(F, V, args)`, write `GetCallable(f).Call(...)` so the failure is a `JavaScriptException` your\n  `Completion` handling can turn into a rejection.\n- **`Promise`-shaped fixes need the abrupt path checked too.** `Completion(...)` wrapping means a throw\n  inside the step becomes a rejection, while a throw from a step *outside* it propagates to the caller. Tests\n  distinguish the two (`ctx-non-ctor.js` expects a synchronous `TypeError`; `throws.js` expects a rejection).\n","frontmatter":{"name":"test262-update","description":"Bump Jint's pinned tc39/test262 SHA in Jint.Tests.Test262/Test262Harness.settings.json, triage the upstream commit range for normative changes, run the conformance suite, and fix whatever the new tests expose. Use when asked to update/upgrade test262, bump SuiteGitSha, pull in the latest conformance tests, or investigate a test262 conformance failure after a bump."},"isInternal":false,"tokens":2484,"sizeBytes":9750}],"systemPromptSnippet":"<yakaai_skills repo=\"sebastienros/jint\">\n<!-- File: AGENTS.md (Tokens: ~5287 | Category: root-instruction) -->\n# Agent Instructions for Jint\n\nJint is a JavaScript interpreter for .NET. It parses JavaScript using the Acornima library (AST), then interprets it directly — no bytecode generation or DLR usage. The pipeline is `Acornima parser → AST → interpreter → runtime → interop`, each AST node wrapped once in a `Jint*` interpreter class that `Engine` walks; the three stages, those wrapper classes and what they return — `Completion` for a statement, `JsValue` or `Reference` for an expression — are in [`Jint/Runtime/Interpreter/AGENTS.md`](Jint/Runtime/Interpreter/AGENTS.md#the-execution-pipeline).\n\nThis is the canonical instruction file for every agent working on this repository; `CLAUDE.md` imports it. Target and compare work against the **`main`** branch, which is also the PR target.\n\n## How these instructions are laid out\n\nThis file is the entry point and is kept small: it holds what every agent needs before its first edit,\nwhatever that edit turns out to be. Everything else lives in an `AGENTS.md` beside the code it governs.\n**Read the file on the row matching what you are about to do, before you touch that code.**\n\n| If you are about to… | Read first | What is in it, and what a violation costs |\n| --- | --- | --- |\n| change a signature or observable behaviour under `Jint/`, or anything outliving one evaluation — `Prepared<T>`, `Options`, a snapshot, the event loop, an `*Async` entry | [`Jint/AGENTS.md`](Jint/AGENTS.md) | The key runtime types, the namespace map, the engine-source conventions (type co-location, the unsigned-cast bounds check, the code patterns, visibility), and where the frozen-contract table lives. Cost: a silent breaking change for embedders, or one engine's state leaking into another through a shared `Prepared<Script>`. |\n| implement or change an ECMAScript built-in, intrinsic, coercion rule or new syntax | [`Jint/Native/AGENTS.md`](Jint/Native/AGENTS.md) | Which spec document is authoritative, and that test262 beats prose. Cost: implementing a dated snapshot or a compatibility table instead of the living spec — or un-gating a web API that must stay opt-in. |\n| touch `ObjectInstance`, a property descriptor, a property-access lane, or anything a host subclasses | [`Jint/Native/Object/AGENTS.md`](Jint/Native/Object/AGENTS.md), and [`Jint/Runtime/Descriptors/AGENTS.md`](Jint/Runtime/Descriptors/AGENTS.md) for the descriptor itself | The subclassing cliff, `PropertyAccessSemantics`, host-contract verification, `ArrayLikeObject` and the host-object shapes one pointer on, who may reach a new fast lane. Cost: sorting every embedder into a slow path they cannot see or escape. |\n| touch CLR interop — wrappers, converters, reference resolvers, dictionary-backed reads, a host `ProxyHandler`, a CLR exception crossing into script, `[JsAccessible]`, a trimming or AOT annotation | [`Jint/Runtime/Interop/AGENTS.md`](Jint/Runtime/Interop/AGENTS.md), plus [`Jint.AotExample/AGENTS.md`](Jint.AotExample/AGENTS.md) for the native leg | Which host registrations silently disable a compiled lane engine-wide, the immutable-crossing promise, why a generated accessor is a compile-time copy of the run-time compiled one, and which generic instantiations degrade rather than throw. Cost: an engine-wide deoptimisation nobody can see, stale reads, or an `IsAotCompatible` claim nothing runs. |\n| change either Roslyn source generator, or an attribute one of them reads | [`Jint.SourceGenerators/AGENTS.md`](Jint.SourceGenerators/AGENTS.md) | Why there are two analyzer assemblies and only one may ever be packed, the consumer-facing Roslyn pin a bump breaks silently, the value-equality the incremental model rests on, and why accepting a snapshot is the only review the emitted C# gets. Cost: a package whose first build error is in code the consumer never wrote. |\n| add or change a statement/expression handler, a fast path in one, coverage, or anything published onto the AST or a `Prepared<T>` | [`Jint/Runtime/Interpreter/AGENTS.md`](Jint/Runtime/Interpreter/AGENTS.md) | Engine-affine vs shareable state and the AST `UserData` invariant, why coverage counters cannot live on a handler node, and what a warmed call site retains. Cost: a fast path that silently stops being counted, or an engine pinning a host object for its lifetime. |\n| touch module loading, linking, evaluation, or a module's location | [`Jint/Runtime/Modules/AGENTS.md`](Jint/Runtime/Modules/AGENTS.md) | The load phase, which failures become rejections and which must stay fatal, the three host entry points and which one deadlocks, `ModuleFactory.LocationOf`. Cost: a widened `catch` turns a constraint into a rejection that bounds nothing. |\n| touch anything bounding execution — statements, time, memory, recursion, cancellation | [`Jint/Constraints/AGENTS.md`](Jint/Constraints/AGENTS.md) | How limits and CLR access are configured, what disarms the tight-loop lane, what a fan-out brackets, why the cancellation cadence is engine state, how `MaxRecursionDepth` counts, saturated sentinels. Cost: a limit that no longer limits. |\n| write a call site needing an API `net472` / `netstandard2.0` / `netstandard2.1` lacks | [`Jint/Extensions/AGENTS.md`](Jint/Extensions/AGENTS.md) | The polyfill-downwards discipline and the ways a polyfill stops being one. Cost: `#if` scattered through spec algorithms, or a downlevel `OrderBy` that spins forever on a comparer JavaScript may legally supply. |\n| touch anything under `Jint/WebApi/` or `Options.WebApi` | [`Jint/WebApi/AGENTS.md`](Jint/WebApi/AGENTS.md) | The four subtree conventions, the whole-file `net8.0` gate, WebIDL's property attributes (enumerable — the opposite of ECMAScript's rule), timer ordering, the diagnostics sink. Cost: a member shipped with the wrong attributes, or a build that breaks only on `net472`. |\n| touch `fetch`, a cookie jar, a redirect hop, or `FetchObserver` | [`Jint/WebApi/Fetch/AGENTS.md`](Jint/WebApi/Fetch/AGENTS.md) | The five settings that make `fetch` a browsing position, per-hop recomputation, the engine-free observer. Cost: a `JsValue` on the transport thread. |\n| write or change a test in the main suite, or read a failure from one of the tests that police this repository | [`Jint.Tests/AGENTS.md`](Jint.Tests/AGENTS.md) | The two assembly attributes six test assemblies share, the rule that a wall-clock number is either the assertion or a wedge ceiling and never both, the helpers that replace xUnit's vocabulary, and the guardian tests no edit to what they check will satisfy. Cost: fixtures that silently share one engine, or a regression hidden by widening a timeout. |\n| touch the vendored web-platform-tests corpus, its shim or its driver | [`Jint.Tests/Wpt/AGENTS.md`](Jint.Tests/Wpt/AGENTS.md) | The exclusion table is the artefact — an entry must match a failing test and no passing one — and a non-zero `NeedsTriage` count means the corpus found a defect somebody still owes the engine a fix for. Cost: five thousand green cases that mean nothing. |\n| run a wpt suite in a real page — the browser lane, its overlay, its wrappers | [`Jint.Tests.Browser/Wpt/AGENTS.md`](Jint.Tests.Browser/Wpt/AGENTS.md) | One corpus and one pin shared with the lane above, upstream's real harness, the results overlay, the five browser-only categories, the census ceiling. Cost: a document that reports nothing counted as a document that passed. |\n| bump the pinned test262 SHA or triage a conformance failure | [`Jint.Tests.Test262/AGENTS.md`](Jint.Tests.Test262/AGENTS.md) | A bump is a code change, not a pin change; and the three exclusion banners, one of which is deliberately not debt. Cost: an upstream normative change landing unread. |\n| write a test proving a third party can reach an API, or read a run that died rather than failed | [`Jint.Tests.PublicInterface/AGENTS.md`](Jint.Tests.PublicInterface/AGENTS.md) | It is the only test project without `InternalsVisibleTo`, which is the whole reason a test there means anything; the table of what counts as a frozen public contract; and what a `TestPipelineException` naming no test actually means. |\n| touch `Jint.DevTools/` — the server, the transport, the protocol pin, the manifest | [`Jint.DevTools/AGENTS.md`](Jint.DevTools/AGENTS.md) | Which thread may touch the engine, the protocol pin and regeneration, the manifest rule. Cost: a command run on the socket thread. |\n| touch a session, a target, the mailbox, or the pause-time message loop | [`Jint.DevTools/Session/AGENTS.md`](Jint.DevTools/Session/AGENTS.md) | How a command crosses to the engine, why a target outlives its engine, what a swap tells each domain, the pause loop. Cost: a domain answering about a document that was replaced. |\n| implement or change a `Jint.DevTools` domain — a command, an event, a handle | [`Jint.DevTools/Domains/AGENTS.md`](Jint.DevTools/Domains/AGENTS.md) | What a client is promised about a value it cannot see, and what may never run script. Cost: a preview that runs a getter. |\n| touch `Jint.HtmlParser/`, parser corpora, generated lookups or its package contracts | [`Jint.HtmlParser/AGENTS.md`](Jint.HtmlParser/AGENTS.md) | Native ownership, inert parsing, defaults and cooperative limits, immutable-read threading, experimental version policy and verification recipes. Cost: Browser work during native parsing, torn reads, or an unverified stable package. |\n| touch the DOM bindings or their generator | [`Jint.Browser/Dom/AGENTS.md`](Jint.Browser/Dom/AGENTS.md) | The explicit binding contract, native adapters, conversion rules, wrapper identity and shape discipline. Cost: a hand-edited `.g.cs`, a stale contract, or an adoption that changes a node's creation brand. |\n| touch anything else under `Jint.Browser/` — the package's principle, an observer, accessibility or extraction, a page budget, what is public | [`Jint.Browser/AGENTS.md`](Jint.Browser/AGENTS.md) | Native parser versus browser ownership, parsing-performance hooks, the LightPanda parity target, generated versus hand-written, observer delivery and public seams. Cost: per-node Browser overhead during parsing, a second DOM store, or a seam published prematurely. |\n| dispatch an event a page can hear, or touch activation, focus, the keyboard or the editor under `Jint.Browser/Events/` | [`Jint.Browser/Events/AGENTS.md`](Jint.Browser/Events/AGENTS.md) | Which algorithm point raises which event, what activation without a layout can be, why the handler content attributes need no notification, and the editor's string and two offsets. Cost: a second event bus, or an event nothing can hear. |\n| touch a page target or a page-level domain under `Jint.Browser/DevTools/` | [`Jint.Browser/DevTools/AGENTS.md`](Jint.Browser/DevTools/AGENTS.md) | A domain reads the target's current runtime per command; the request log the protocol shares with `Page.Requests`. Cost: answering about a replaced document. |\n| touch the accessibility tree or the text/markdown extractors under `Jint.Browser/Accessibility/` or `Extraction/` | [`Jint.Browser/Accessibility/AGENTS.md`](Jint.Browser/Accessibility/AGENTS.md) | html-aam roles and names without layout, what `hidden` means, what a snapshot promises. Cost: a role computed from a box that does not exist. |\n| touch a page — its loop, a navigation, a form, history, storage, a worker, a budget, a box | [`Jint.Browser/Runtime/AGENTS.md`](Jint.Browser/Runtime/AGENTS.md) | The one thread that owns a page's engine and its DOM, why a navigation is a fetch off the loop and a new engine on it, what a turn is, the flat box model. Cost: a second thread in the DOM. |\n| touch the parser driver — how a document, script, module or style sheet loads — or a child frame's window | [`Jint.Browser/Runtime/Parsing/AGENTS.md`](Jint.Browser/Runtime/Parsing/AGENTS.md) | Cooperative native parsing on the page loop, resource pumping, frame realms and scheduling divergences. Cost: script in a native mutation callback, or unrelated tasks inside a parser yield. |\n| touch the `jint-browser` command line, or its tests | [`Jint.Browser.Tool/AGENTS.md`](Jint.Browser.Tool/AGENTS.md) | Why it may never take an `InternalsVisibleTo` grant, the seams that pressure promoted, the exit-code contract, how a tool package is packed. Cost: a seam reached around instead of published. |\n| touch the Model Context Protocol server — a tool, its description, a result | [`Jint.Browser.Mcp/AGENTS.md`](Jint.Browser.Mcp/AGENTS.md) | Why a description is the product, why every tool answers rather than throws, and why stdio is the only transport. Cost: a failure an agent is told nothing about. |\n| write, run, or quote a benchmark number | [`Jint.Benchmark/AGENTS.md`](Jint.Benchmark/AGENTS.md) | The measurement environment and its three modes, the paired comparison, one engine per row. Cost: a `--job short` number in a PR, or a row that depends on its siblings. |\n\nBefore adding to any of them, read [the size budget](#the-size-budget-and-which-agents-load-what) at the end of this file: keep this one under 24 KiB and each of those under 32 KiB, which `dotnet test` fails on rather than merely states.\n\n## Build & Test\n\n```powershell\n# Build (solution, or a single project)\ndotnet build -c Release\ndotnet build -c Release Jint/Jint.csproj\n\n# Run all tests\ndotnet test -c Release\n\n# A specific project (no --timeout: MTP's --timeout bounds the WHOLE run, not one test, and a full\n# Jint.Tests run takes minutes per framework - a 30 s cap ends it early while still printing \"Passed!\")\ndotnet test --project Jint.Tests\\Jint.Tests.csproj -c Release\n# A class or a single test, where a whole-run cap is a sane wedge ceiling\ndotnet test --project Jint.Tests\\Jint.Tests.csproj -c Release --filter \"FullyQualifiedName~Jint.Tests.Runtime.EngineTests\" --timeout 30s\ndotnet test --project Jint.Tests\\Jint.Tests.csproj -c Release --filter \"FullyQualifiedName~Jint.Tests.Runtime.EngineTests.CanAccessCLR\" --timeout 30s\n\n# Test262 conformance suite\ndotnet test -c Release --project Jint.Tests.Test262\\Jint.Tests.Test262.csproj\n```\n\nAlways build and test in **Release** — it is the faster feedback loop and the configuration performance claims are about. Never pass `--no-build`; always work against freshly compiled code. `TreatWarningsAsErrors` is on, so every warning must be fixed. Packages are managed centrally through `Directory.Packages.props`.\n\n`global.json` selects Microsoft Testing Platform v2 for all NUnit test projects.\nUse `--project` for a project path and pass runner options directly, without VSTest's\n`--` separator. Local runner, filtering and parallelism details are in\n[`Jint.Tests/AGENTS.md`](Jint.Tests/AGENTS.md#local-microsoft-testing-platform-runs).\n\nA separate leg runs `Jint.Tests` and `Jint.Tests.PublicInterface` with the host-contract verifiers on\n(`JINT_HOST_CONTRACT_VERIFICATION=1`), the configuration an embedder is told to use. For a quick manual run\nbefore a test exists there is `Jint.Repl`, and **always pass `-t`** so a runaway script cannot hang the\nsession; anything worth keeping becomes a test — in one of eight projects, and the one a change needs is\noften not the one it edits: a conformance failure is never \"fixed\" in `Jint.Tests.Test262`, and a test only\nproves a third party can reach an API in `Jint.Tests.PublicInterface`. What each project holds, the runner\ntimeout each needs, why that verification leg is not the default and the `Jint.Repl` invocations are all in\n[`Jint.Tests/AGENTS.md`](Jint.Tests/AGENTS.md#the-eight-test-projects-and-which-one-a-test-belongs-in).\n\n## Third-party integration surface\n\nJint is not only an engine to work on, it is an engine that gets **embedded**. Integrators host it in-process, project host-supplied objects into script, and bound execution. A significant part of the public API exists only to serve them, and for everything in this section **changing observable behaviour is breaking even when the signature is untouched**. Assume an embedder depends on it before simplifying or \"optimising\" it.\n\nIts rules are split across the files in the index above, and every one of them is in one of those. Four stay here, because they are the ones an agent breaks *before* it knows which file to open — each looks like an ordinary internal refactor right up to the moment an embedder's bounded execution stops being bounded.\n\n### Gotchas\n\nEach of these cost a real integrator or a real bug.\n\n- **Constraints bound one entry into the engine, never a host-driven sequence of them.** Every public entry that runs script — `Execute`, `Evaluate`, `Invoke`, `Engine.Call`, the `JsValue.Call` extension helpers — funnels through `Engine.ExecuteWithConstraints` (`Jint/Engine.cs`), which calls `ResetConstraints()` before the callback and again in its `finally` for any entry that is not nested. So `foreach (var row in rows) predicate.Call(row);` — the single most common embedding shape — hands every element a fresh statement budget, a fresh allocation budget and, worst, a **freshly armed timeout deadline**. Measured: `LimitStatements(100)` does not stop 1000 host `Call`s, `LimitExecutionTime(200ms)` does not fire across 3 s of continuous host-driven execution, and `LimitMemory` never sees more than one call's allocations — while the identical work inside one `Execute` throws in every case. What no embedder expects is that a single function call is a **run**. `Engine.Constraints.Check()` from the host loop does not close the gap either. **What an embedder must do instead — the host-side bound, the in-script loop, and the two in-box constraints that survive the per-entry reset — is [`Jint/Constraints/AGENTS.md`](Jint/Constraints/AGENTS.md#bounding-a-host-driven-sequence), which is also the file to read before changing any of it.**\n- **`DefineOwnPropertyUnchecked` / `DefineOwnDataPropertyUnchecked` always create an *own* property.** They shadow anything of that name on the prototype chain, invoke no inherited setter, and run no `[[DefineOwnProperty]]` validation (so they can never raise `TypeError`) — and storing a raw descriptor under a string key deoptimizes an ordinary hidden-shape receiver, forfeiting its shape inline cache. When to reach for them, and the three cases a shared built-in shape can keep, are in [`Jint/Native/Object/AGENTS.md`](Jint/Native/Object/AGENTS.md#the-unchecked-defines-when-to-reach-for-them).\n- **The enumeration hook is `GetOwnPropertyKeys`, and it is the only one.** `GetOwnProperties` was a second `virtual` whose name read like the hook, and a real integrator overrode only that and shipped an object whose keys were invisible to every script-visible enumeration; since [#3461](https://github.com/sebastienros/jint/pull/3461) it is derived from `GetOwnPropertyKeys` + `GetOwnProperty` and non-virtual, so a host declares its keys once. Which consumers read it, and what a host overrides instead, are in [`Jint/Native/Object/AGENTS.md`](Jint/Native/Object/AGENTS.md#the-enumeration-hook-what-a-host-overrides-instead).\n- **Sharing a `JsValue` across engines is unsupported**, and nothing validates or guards it. An `ObjectInstance` holds a hard reference to its creating engine and realm. Where that *is* written down, and what a fix owes, are in [`Jint/AGENTS.md`](Jint/AGENTS.md#gotchas).\n\nThe rest are in the files indexed above. **Do not add a new gotcha here.** Add it to the file for the area it governs; if none fits, say so in the pull request rather than growing this one.\n\n## Conventions\n\nGlobal usings for Acornima and `Acornima.Ast` are defined in `Directory.Build.props`. Nullable reference types are enabled across the codebase, unsafe code is allowed for performance-critical paths, and the latest analyzers run with `EnforceCodeStyleInBuild`.\n\n### Performance is critical, and the conventions live beside the engine\n\nPerformance is a first-class concern; every change must consider its impact. The checklist that answers it\n— inlining on hot paths, `readonly struct`, `Span<T>` and stack allocation, the `Jint.Pooling` pools,\n`sealed`, `internal`, caching `Prepared<Script>` — sits with the rest of the code patterns (lazy\ninitialization, the `Throw.*` helpers, XML docs, type flags, spec references), the data-structure rule and\nthe internal-first visibility ladder in [`Jint/AGENTS.md`](Jint/AGENTS.md#code-patterns). Two of those bind\nbefore that file is open: cite the spec section a change implements, and default every new member to the\nnarrowest visibility that compiles.\n\n## The size budget, and which agents load what\n\nKeep this file under **24 KiB** and every co-located file under **32 KiB**. Both numbers come from what the\ntools actually do; the per-tool table of which file each agent loads, and the Codex and Devin caps the\nnumbers are taken from, are in [`docs/agent-instruction-files.md`](docs/agent-instruction-files.md).\n\n**When this file is the one that has to shrink, the cut is a trap/remedy split, not a trim.** A gotcha\nstates what an agent breaks before it knows which file to open; the recipe for what to do instead is only\nactionable once that file is open, so it belongs there with a pointer back. That is how the constraints\ngotcha above was split, and it is the first thing to try before anything is shortened or the caps are\ntouched — raising a cap makes Codex's truncation worse, not better.\n\nMost agent ecosystems never reach a co-located file on their own and arrive only because the index names it\n(which of them descend is the last column of that page's table) — which is why the index has a trigger column\nrather than being a list of links, and why anything an agent must obey *before* it knows which area it is in\nhas to stay in this file.\n\n**`Jint.Tests/AgentInstructionFileTests.cs` is what makes those two numbers fail rather than merely be\nstated**, since the truncation is silent and nobody was measuring by hand. What it counts, what else it\nholds together and what its failure hands you are in\n[`docs/agent-instruction-files.md`](docs/agent-instruction-files.md#what-makes-the-budget-fail-rather-than-merely-be-stated).\n\n<!-- File: .claude/skills/test262-update/SKILL.md (Tokens: ~2484 | Category: anthropic-skill) -->\n---\nname: test262-update\ndescription: Bump Jint's pinned tc39/test262 SHA in Jint.Tests.Test262/Test262Harness.settings.json, triage the upstream commit range for normative changes, run the conformance suite, and fix whatever the new tests expose. Use when asked to update/upgrade test262, bump SuiteGitSha, pull in the latest conformance tests, or investigate a test262 conformance failure after a bump.\n---\n\n# Updating the pinned test262 suite\n\nThe visible change is one line — `SuiteGitSha` in `Jint.Tests.Test262/Test262Harness.settings.json`.\nTreat it as a **code** change anyway. Upstream lands tests for normative changes that Jint has not\nimplemented, and those turn green features red. The whole job is triaging the range before you run\nanything, then fixing the engine — never the tests.\n\n## Ground rules\n\n- **Never edit or \"fix\" a test262 test.** If a test is wrong, the answer is an engine fix or, as a last\n  resort, an `ExcludedFiles` entry.\n- **test262 at the pinned SHA outranks the published prose.** See [Normative changes](#3-normative-changes--the-part-that-actually-costs-time).\n- Exclusions outside `intl402/` must be temporary and carry a comment naming what removes them. Today every\n  `ExcludedFiles` entry is intl402 — keep that invariant.\n- A feature that arrives unimplemented parks in `ExcludedFeatures`; the PR that implements it removes the entry.\n- Work in a worktree, not the primary checkout, and start from a fresh `main`.\n\n## 0. Orient\n\n| Thing | Where |\n| --- | --- |\n| The pin | `Jint.Tests.Test262/Test262Harness.settings.json` → `SuiteGitSha` |\n| Local suite checkout (read-only aid) | `../test262` — `origin` = your fork, `upstream` = `tc39/test262` |\n| Generator | `dotnet test262 generate`, from `Jint.Tests.Test262/.config/dotnet-tools.json` |\n| Generated tests | `Jint.Tests.Test262/Generated/` — **gitignored**, so the committed diff stays one line |\n\nThe runner does **not** read `../test262`. `State.Test262StreamLoader` downloads the suite from GitHub at\n`SuiteGitSha`, so the local checkout exists only so you can read the range. Fetch it anyway — you cannot\ntriage without it.\n\nThe `GenerateTestSuite` MSBuild target hashes the settings file and the tool manifest into\n`Generated/.settings.hash`. Change any byte of either and the next build wipes `Generated/` and regenerates.\nSo: never pass `--no-build`, and if you suspect a stale generation, check the hash file rather than guessing.\n\n## 1. Establish the range\n\n```bash\ncd ../test262 && git fetch upstream\ngit log --oneline <pinned-sha>..upstream/main            # or ..<target-sha> if one was given\ngit diff <pinned-sha>..upstream/main -- features.txt\ngit diff --name-only <pinned-sha>..upstream/main | grep -v '^test/'\n```\n\n**Order commits by ancestry, never by author date.** test262 merges rebased branches, so a commit *authored*\nearlier routinely lands on top of one authored later — a real bump had `3655e746` (authored 08-03) sitting\nabove `be13516f` (authored 08-07). Use `--pretty='%h %cd %s'` or `git merge-base --is-ancestor` when the\nordering matters, and confirm the true remote tip with `git ls-remote https://github.com/tc39/test262.git main`.\n\n## 2. Triage every commit\n\nRead the commits, not just the changed-file list.\n\n| Signal | Meaning |\n| --- | --- |\n| only `.github/**`, `tools/**`, `package.json` | infra — zero impact on the run |\n| `features.txt` gained a line | a new feature; if Jint lacks it, it parks in `ExcludedFeatures` with a comment |\n| `src/**.case` / `src/**.template` | procedurally generated tests changed; read the generated output, not the template |\n| new files under `test/built-ins/**` or `test/language/**` | **the risky class** — go to step 3 |\n| a commit message naming a proposal, \"normative\", or an `ecma262#NNNN` | **stop and read the algorithm diff** |\n\nFor a small range, just read the new tests — `git show <sha>:test/path/to/new-test.js`. A test's `info:` block\nusually quotes the numbered algorithm verbatim, which is the fastest way to see what changed and the most\nreliable way to get argument-validation order right.\n\nFor each new behavioural test, check the engine **before** running the suite. `Jint.Repl` turns a 3-minute\nsuite run into a 10-second answer:\n\n```bash\ndotnet run --project Jint.Repl -c Release -- -f scratch.js -t 10   # always pass -t\n```\n\nWrite the assertions as plain `if (…) throw new Error('FAIL …')` — the REPL has no test262 harness. Strip the\n`$DONOTEVALUATE()` / `includes:` lines; for `flags: [async]` tests, assert on `.then(...)` callbacks.\n\n## 3. Normative changes — the part that actually costs time\n\n**The published spec can be behind test262.** A normative PR that reaches consensus gets test262 coverage\nwhile `tc39.es/ecma262` still renders the old algorithm, and an already-merged proposal's own page\n(`tc39.es/proposal-*/`) is frozen at its pre-merge text and will confidently show you the wrong steps. Both\nhappened on the `Promise.try` bump: the proposal page and the living spec agreed with each other and with\nJint, and all three were what the new tests were written to reject.\n\nFind the real change through the repo, not the rendered spec:\n\n```bash\ngh api -X GET search/issues -f q='repo:tc39/ecma262 <feature> <keyword>' \\\n  --jq '.items[] | \"\\(.number) \\(.state) \\(.title)\"'\ngh pr view <n> --repo tc39/ecma262 --json title,state,mergedAt,labels\ngh pr diff <n> --repo tc39/ecma262        # the spec.html algorithm diff is the authority\n```\n\nLabels tell you the status: `has consensus` + `needs implementations` means implement it. `mergedAt: null` is\n**not** a reason to skip — AGENTS.md is explicit that where prose and test262 disagree, test262 at the pinned\nSHA wins.\n\nWhen you implement one:\n\n- Cite the document that owns the feature now. A merged proposal moves to `https://tc39.es/ecma262/#sec-...`;\n  the anchors get renamed on the way in.\n- Add a `<remarks>` naming the normative PR, so the next reader knows why the code and the current published\n  prose disagree.\n- **Re-check the paths the reorder newly reaches.** Moving a step can expose a latent bug that the old\n  ordering made unreachable — see the gotchas below, where hoisting a call above a capability construction\n  turned a dormant `Promise.try()` crash into a live one.\n\n## 4. Bump, build, run\n\n```bash\n# edit SuiteGitSha, then:\ndotnet test -c Release Jint.Tests.Test262/Jint.Tests.Test262.csproj\n```\n\nThe build regenerates before it compiles; no separate generate step. ~3 minutes, ~99.9k tests. No runner\ntimeout needed — the engine defaults to 30 s per test.\n\nVerify the regeneration actually happened rather than trusting a green run over a stale `Generated/`:\n\n```bash\ngrep -c \"<new-test-name>\" Jint.Tests.Test262/Generated/Tests262Harness.Tests.language.generated.cs\n```\n\nA negative parse test appears **twice** per file (strict + sloppy). Deleted upstream tests should be gone.\n\nThen, because a spec fix moves engine behaviour that unit tests pin:\n\n```bash\ndotnet test -c Release Jint.Tests/Jint.Tests.csproj\ndotnet test -c Release Jint.Tests.PublicInterface/Jint.Tests.PublicInterface.csproj\n```\n\n## 5. Fixing what fails\n\nFailure output contains the failing script — strip the line numbers to reproduce it in `Jint.Repl`. Put a\nregression test in `Jint.Tests` for anything test262 does **not** cover (test262 tests the spec, not Jint's\ninternals; a crash on an input no test262 test exercises still needs a pin).\n\n## 6. Decide whether there is a PR at all\n\nIf the suite is green with only the pin moved, there is nothing to ship but a one-line pin bump — say so and\nask before opening a PR. A bump that needs engine fixes is a real PR: pin + fix + regression tests, targeting\n`sebastienros/jint` `main`.\n\n```bash\ngh pr create --repo sebastienros/jint --head <you>:<branch> --base main\n```\n\nKeeping the local suite fork current is a separate, optional courtesy:\n\n```bash\ncd ../test262 && git fetch upstream && git merge --ff-only upstream/main   # then push origin main if wanted\n```\n\n## Gotchas this task has actually hit\n\n- **Author date lies about ordering.** `%ad` is not topology; use `%cd` or `--is-ancestor`.\n- **The proposal page is frozen at merge.** `tc39.es/proposal-promise-try/` still shows the pre-normative\n  algorithm. Never cite it as current for a merged feature.\n- **`spec.html` is too big for a fetch tool.** Asking a fetcher for one section of the living spec returns a\n  truncated prefix and a confident \"not found\". Go through `gh pr diff` instead.\n- **A reorder exposes latent bugs.** `Promise.try` moved `NewPromiseCapability` after the callback call; the\n  argument-slicing that the old ordering never reached with zero arguments then crashed.\n- **`arguments.AsSpan()` is a trap in a built-in.** `ExpressionCache.ArgumentListEvaluation` hands the callee\n  `Unsafe.As<JsValue[]>(object?[])` whenever the argument list is fully cached — *including the zero-argument\n  case* — so `AsSpan()` throws `ArrayTypeMismatchException` (\"Attempted to access an element as a type\n  incompatible with the array\"). Use `arguments.Skip(n)`, which copies element-wise and returns `[]` when\n  there is nothing to take.\n- **`JsValue.Call` on a non-callable throws a CLR `ArgumentException`, not a JS `TypeError`.** Where the spec\n  says `Call(F, V, args)`, write `GetCallable(f).Call(...)` so the failure is a `JavaScriptException` your\n  `Completion` handling can turn into a rejection.\n- **`Promise`-shaped fixes need the abrupt path checked too.** `Completion(...)` wrapping means a throw\n  inside the step becomes a rejection, while a throw from a step *outside* it propagates to the caller. Tests\n  distinguish the two (`ctx-non-ctor.js` expects a synchronous `TypeError`; `throws.js` expects a rejection).\n</yakaai_skills>"}