Skip to content

Docs: give v5 a migration guide, and the README the branches it actually has - #3294

Merged
lahma merged 1 commit into
sebastienros:mainfrom
lahma:docs/v5-migration-guide
Aug 23, 2026
Merged

lahma merged 1 commit into
sebastienros:mainfrom
lahma:docs/v5-migration-guide

Conversation

@lahma

@lahma lahma commented Aug 23, 2026

Copy link
Copy Markdown
Collaborator

main is 181 commits past v4.16.0 and nothing records what an embedder has to react to. The
awkward part is that most of it is invisible to a compiler — every entry in the new document still
compiles exactly as it did in 4.16 and behaves differently at run time, and six of them flip a
default. A host that upgrades and runs its tests will see CLR writes stop working, projected arrays
stop being live, Atomics.wait throw, importNamespace fail on its own assembly, and error
messages go generic, with nothing to search for.

This adds docs/v5-migration.md as the place those entries live, seeds it with what is already on
main, and gives the README the branch table it should have had since 4.x was cut.

docs/v5-migration.md

Deliberately not a second README: a table per change, before/after code where it helps, and the
rationale left in the pull request it cites. A migrating reader wants to know what broke and what to
type instead.

Section 4, "Breaking without a signature change", is the one with content. Every claim was
checked against the tree — the defaults against v4.16.0:Jint/Options.cs, the behaviours against
the tests that pin them — rather than against the pull request titles:

PR Setting 4.16.x 5.x
#3054 Interop.AllowWrite true false
#3056 Interop.ArrayConversion LiveView Copy
#3057 Constraints.StackOverflowGuard false true
#3058 AgentCanSuspend true false
#3051 script-visible CLR / module error text detailed redacted
#3052 namespace type discovery implicit assembly search closed allow-list

plus the four that change behaviour without a setting to point at: #3035 (concurrent Engine use
rejected, and an engine reserved for the lifetime of a returned async Task), #3036 (LimitMemory
charged across async continuations, so a budget can trip where one synchronous segment never reached
it), #3252 (one deterministic *Async failure channel), #3248 (an array-like length above 2^32−1
answering the same on every target framework).

The rest of the security stack — #3037, #3045, #3046 — is grouped as new limits that all default to
unlimited
, because that is what they are: they change nothing until a host configures them, and the
guide says so rather than implying a break. #3059 and #3060 sit beside them as entirely opt-in.

Sections 2, 3 and 6 are explicit empty placeholders, each with a one-line note saying what fills
it. Nothing public has been removed or renamed since v4.16.0 — checked, including that no
[Obsolete] was added — and a parallel task is measuring the AOT state.

Section 1, target frameworks, is written and marked pending. Jint/Jint.csproj still lists
net462; the net472 change is not on main yet, so the section carries a status blockquote rather
than claiming something the tree does not do.

Jint/AGENTS.md

One paragraph under What counts as a public contract: a change to anything in that table is a row
in the guide, written in the same pull request, including a change that breaks nothing at compile
time. Without it the document is a snapshot that rots. The root AGENTS.md is untouched — it is at
23 KB against a hard 24 KiB budget — and Jint/AGENTS.md goes from 27,276 to 27,618 bytes against
its 32 KiB one.

README.md

"Branches and releases" documented main alone and did not mention 3.x at all. It now has a row
per live branch (main = 5.x development and the PR target, 4.x = the 4.16.x maintenance line,
3.x = the Esprima-era line) plus how a release is cut, in the same wording #3291 gives the 4.x
branch's own copy
so the two branches say the same thing, and a pointer to the migration guide.

One thing for a reviewer to note: the MyGet bullet names 4.x alongside main and 3.x, which
becomes true when #3291 lands — main's own .github/workflows/build.yml push filter still reads
[ main, 3.x ]. That filter governs pushes to main only (GitHub runs the workflow file from the
pushed branch), so nothing here depends on changing it, but say the word if you would rather main's
copy listed 4.x too.

Two places the history did not say what I was told it said

Both are written as the tree has them, and both are worth flagging because the wrong version reads
plausibly:

  • The stack-overflow guard raises RangeError: Maximum call stack size exceeded — an ordinary
    JavaScript error the script itself can catch — not a RecursionDepthOverflowException.
  • ArrayOperations is internal, so LengthOfArrayLike: delete the uint overload rather than clamp it #3248 removes no public member. Its break is entirely what
    a script sees (Array.from({length: 2**53}) now raises ArrayCreate's RangeError;
    new Uint8Array(4).set([1], 1e20) stops silently succeeding on net472), which is why it is in
    section 4 and not in the removed-API table.

Also worth knowing for anyone repeating this exercise: the security-stack commits (#3035–#3060) carry
title-only squash messages, so their reasoning is in the pull request bodies rather than in
git log. The later ones (#3248, #3252) carry the full account in the commit itself.

Verification

  • dotnet build -c Release on the solution — unchanged, no code touched.
  • Every relative link and anchor in the new document resolves, checked mechanically against GitHub's
    slug rules over README.md, .github/THREAT_MODEL.md and the document's own headings.
  • Every API name quoted in the guide grepped in the tree: AllowClrWrite, ArrayConversionMode,
    StackOverflowGuard, AgentCanSuspend, ExposeDetailedErrors, AllowedAssemblies,
    AllowGetType, ResultLimits, Advanced.ConvertResult, MemoryLimitAccuracy,
    ParsingLimitException, ModuleGraphLimitException, ResultLimitExceededException,
    ValidateSecurityConfiguration, ForUntrustedCode, UseWebApis, UseWorkers, UseNodeProcess,
    UseNodeBuiltinModules, Profiling.Enabled, Coverage.Enabled.
  • Every "4.16 was X" claim diffed against the v4.16.0 tag rather than remembered.

🤖 Generated with Claude Code

https://claude.ai/code/session_014W5mbjGhyvgAS4pivXoc4S

…lly has

Main has moved 181 commits past v4.16.0 and nothing records what an embedder
has to react to. Most of it is invisible to a compiler: every entry below still
compiles exactly as it did in 4.16 and behaves differently at run time, and six
of them flip a default.

`docs/v5-migration.md` is the artefact those entries go in. It is deliberately
not a second README: a table per change, before/after code where it helps, and
the rationale left in the pull request it cites.

Seeded from git history, every claim checked against the tree rather than
against the pull request title:

  * sebastienros#3054 `Interop.AllowWrite` true -> false. A projected CLR write is now
    silently ignored in sloppy mode and a TypeError in strict mode.
  * sebastienros#3056 `Interop.ArrayConversion` LiveView -> Copy. `Array.isArray` flips to
    true, `push`/`length` stop throwing, and CLR-side mutations after the
    crossing stop being visible.
  * sebastienros#3057 `Constraints.StackOverflowGuard` false -> true. RangeError instead of
    a process that ends with no exception in the log.
  * sebastienros#3058 `AgentCanSuspend` true -> false. `Atomics.wait` is a TypeError before
    a waiter is registered; `waitAsync` is untouched.
  * sebastienros#3052 namespace type discovery loses its implicit fallback to
    `Assembly.GetCallingAssembly()` / `GetExecutingAssembly()` /
    `Type.GetType(name)` and becomes the `AllowedAssemblies` allow-list.
  * sebastienros#3051 host exception, module-load and CLR-resolution messages are redacted
    from script; `ExposeDetailedErrors()` restores all three.
  * sebastienros#3035 concurrent `Engine` use fails fast, and an engine stays reserved for
    the lifetime of a returned async Task.
  * sebastienros#3036 `LimitMemory` charges allocations across async continuations, so a
    budget can now trip where one synchronous segment never reached it.
  * sebastienros#3252 every `*Async` entry reports the operation's failures through the
    task and only a usage error out of the call.
  * sebastienros#3248 an array-like `length` above 2^32-1 stops answering differently per
    target framework.
  * sebastienros#3037, sebastienros#3045, sebastienros#3046 add parser, module-graph and result bounds that all
    default to unlimited, so they change nothing until configured; sebastienros#3059 and
    sebastienros#3060 add the diagnostics and the hardened profile on top.

Two entries the prompt for this work had slightly differently, both checked and
written as the tree has them: the stack-overflow guard raises a catchable
`RangeError`, not a `RecursionDepthOverflowException`, and `ArrayOperations` is
internal, so sebastienros#3248 removes no public member — its break is what a script sees.

Sections 2, 3 and 6 (removed API, renamed API, AOT) are explicit empty
placeholders. Nothing public has been removed or renamed since v4.16.0, and a
parallel task is measuring the AOT state.

The target-framework section is written and marked pending: `Jint.csproj` still
lists net462, and the net472 change is not on main yet.

`Jint/AGENTS.md` gains the rule that makes the guide stay current — a change to
anything in its public-contract table is a row in the guide, in the same pull
request, including a change that breaks nothing at compile time. The root
`AGENTS.md` is untouched; it is at 23 KB against a 24 KiB budget.

README's "Branches and releases" described `main` alone and did not mention the
`3.x` branch at all. It now has a row per live branch, in the same wording
sebastienros#3291 gives the 4.x branch's own copy, plus a pointer to the guide.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014W5mbjGhyvgAS4pivXoc4S
@lahma
lahma force-pushed the docs/v5-migration-guide branch from 9f076a0 to da6d433 Compare August 23, 2026 10:55
@lahma
lahma merged commit 1ee5113 into sebastienros:main Aug 23, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant