docs(#4157): architect specs for #4405 + #4406, and #4414 (devirtualized boolean-return miscompile) - #4511
Merged
Merged
Conversation
Measured on recover/levers-integration @ a57876a via the standalone acorn compile lane. Key finding: the whole-program `this`-receiver inference the issue asks for is already shipped (#3683 S1-S4, #3754, #3780) and runs at 97.9% coverage — 488 twins, 1,580 inlined this.<f> ops, 34 declines. The measured residual is on the NON-this axis: 4,064 non-this receivers asked, 244 proven (6.0%), 88 inlined; zero write-side emitter; acorn's __fnctor_Node carries only type/start/end so the AST payload lives in $resid. Re-scopes the issue to non-this receivers and phases it into four landable PRs (census / proof coverage / struct shape / write side). Rejects the issue's guard-free requirement for the inferred axis and keeps the ref.test, per the codebase's own guardedReceiver argument. Corrects five stale assumptions, including that JS2WASM_IC_GUARD_REUSE does not exist and that entry 39's cited 19.5x baseline is absent from the record on this branch. Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
…t the proposed fix ✓ Measured on main: only the prototype-method call shape miscompiles (literal booleans, local booleans and plain function calls are all correct), and only JS2WASM_DIRECT_CALLS=0 repairs it — NUMERIC_TWINS=0 and TYPED_THIS=0 do not. The isBooleanish veto this issue proposed was implemented and measured: the repro is unchanged, so it is not the root cause. Co-Authored-By: Claude <noreply@anthropic.com>
…o its localized cause ✓ The id 4407 collided with 4407-react-dom-wasm-capture already on main (the allocation ran with a degraded PR scan, which warns about exactly this). Reallocated to #4414 via claim-issue --allocate. Retitled because the localization in this file disproved the original framing: the isBooleanish veto on the numericFunctions fixpoint was tried and left the repro byte-for-byte unchanged. The defect lives in the direct-call devirtualization result-type choice (JS2WASM_DIRECT_CALLS=0 fixes it; typed-this and numeric twins off do not). Co-Authored-By: Claude <noreply@anthropic.com>
…work ✓ Captures the 2026-08-14 session so it can be resumed in another container: what landed (#4455 flip + 3 CI PRs), the local order-reversed A/B confirming -13.3% (and why the npm-compat dashboard cannot resolve it), the fresh paired profile decomposition, per-function targets, the two DIFFERENT reasons fullCharCodeAt and currentVarScope are not inlined, open work with branches, and the environment hazards that cost work today. Co-Authored-By: Claude <noreply@anthropic.com>
ttraenkler
pushed a commit
that referenced
this pull request
Aug 16, 2026
1 task
ttraenkler
added a commit
to ttraenkler/js2
that referenced
this pull request
Aug 16, 2026
…che, suspend sentinel, agent-spawn deny hook ✓ Implements the suspend-at-99% rule as automation (user directive 2026-08-16): the statusline budget cache now persists the FIVE_HOUR window (pct + reset), a singleton daemon polls it every 60s and raises/clears ~/.claude/usage-limit-suspend.json at >=99%, a SessionStart hook launches the daemon, and a PreToolUse hook DENIES new Agent spawns while the sentinel is live — the deny reason carries the suspend order and the reset time. Headless sessions (no statusline renders) degrade to an explicit NO-SIGNAL log state, never a fabricated percentage; the limit-error fallback stands there. All four paths pipe-tested (raise / deny / clear / no-signal); settings merge validated with jq. Also files loopdive#4509 (test262 print shim couples the console claim surface to every suite compile once param types resolve) and loopdive#4510 (pre-claim -> post-claim demote drift in the standalone baseline), both from the dev-4605-park diagnosis that refuted the stale-base park. Co-Authored-By: Claude <noreply@anthropic.com>
ttraenkler
pushed a commit
to ttraenkler/js2
that referenced
this pull request
Aug 16, 2026
…itor feat(loopdive#4511): session-start usage-limit monitor — 5h-window cache, suspend sentinel, agent-spawn deny hook
ttraenkler
added a commit
that referenced
this pull request
Aug 16, 2026
Every `ComputedPropertyName` in an object literal used to reject the whole
containing function at `objectlit-computed-key` — including `{ ["a"]: 1 }`,
whose key is a string literal and is indistinguishable from `{ a: 1 }` after
folding. Legacy already folds (`resolveComputedKeyExpression` →
`resolveConstantExpression`) and compiles the result to the same closed struct.
The IR object shape is static, so the adoptable set is exactly the keys that
resolve to a string during selection. The selector is checker-free (bare
`SourceFile`; its `scope` is a name set, not a value environment), so the fold
is purely syntactic: string literal, no-substitution template, numeric literal,
and parenthesised wrappers of those. Keys needing a value environment —
`const k = "a"`, `Symbol.iterator`, template substitution, arithmetic — keep
rejecting at the same arm. No new reject code minted.
New leaf module `src/ir/property-key-fold.ts` holds the single fold that both
`select.ts` and `from-ast.ts` call. The two files cannot import each other, and
a duplicated *widening* fold could drift into a post-claim `invariant` (selector
claims, lowerer cannot deliver). It is applied at the object-literal
data-property site only, not to `phase1PropertyName`, whose 7 other call sites
are class-member / method naming where a computed name means something else.
Measured, not assumed:
- A `String(Number(text)) === text` canonicality guard was written first, on the
premise that `.text` for `{ [0x10]: v }` is raw `"0x10"`. It is not —
TypeScript's scanner already stores the canonical decimal form (16 spellings
verified: `0x10`→`16`, `0b101`→`5`, `0.50`→`0.5`, `1e3`→`1000`,
`1e21`→`1e+21`, …). The guard was dead code documenting a rejection that
never happened; the sweep caught it because three cases drafted as negatives
came back claimed. Removed, and replaced by a runtime assertion that
`{ [0x10]: v }` / `{ 0x10: v }` / `{ 16: v }` are the same key.
- Evaluation order: `lowerObjectLiteral` sorts the field list by name, but only
after every initializer has been lowered in source order. A computed key makes
that distinction visible, since a folded name need not sort in source
position. Pinned with the #4459 counter idiom — `{ ["b"]: p(1), a: p(2) }`
reads 12, not 21.
- `{ a: 1, ["a"]: v }` now rejects at `objectlit-duplicate-key` rather than
`objectlit-computed-key`: still rejected, more precisely labelled.
Acceptance sweep: 30 shapes, each claimed-and-emitted with legacy/IR parity or
cleanly rejected; a single `invariant` fails. PASS — 0 bad of 30, 18 claimed
(12 before). `check:ir-fallbacks` and `check:ir-only` A/B'd against base copies:
unchanged in both directions. tests/issue-4511.test.ts (28), neighbours #4471 /
#4459 (62), equivalence shards 1–8, and the `quality` ratchets all pass.
Co-Authored-By: Claude <noreply@anthropic.com>
✓
ttraenkler
added a commit
that referenced
this pull request
Aug 16, 2026
…ision ✓ `claim-issue.mjs --allocate` reserved #4511 with `pr_scan="degraded"` (gh unavailable in this container, so the open-PR id universe was not consulted). While this branch was in flight, `1efe399b` landed the session usage-limit monitor on main as #4511 — exactly the collision the degraded scan warns about, and the one `check:issue-ids:against-main` exists to catch before the merge queue does. Renumbered to a freshly reserved #4513: issue file, test file, and every `#4511` reference in `src/ir/property-key-fold.ts`, `src/ir/select.ts`, `src/ir/from-ast.ts` and the `ObjectLiteralExpression` row in `scripts/gen-ir-adoption.mjs` (table regenerated). No behaviour change. Co-Authored-By: Claude <noreply@anthropic.com> ✓
ttraenkler
added a commit
that referenced
this pull request
Aug 16, 2026
…ision ✓ - `check:ir-only` on the merged tip reads 22 emitted / 15 unsupported on the standalone lane vs 19 / 18 before the merge. That delta is main's, not this branch's: the pre-merge A/B against the `.tmp/4513/base/` revert copies read 19 / 18 both with and without the change. Recording which run attributes what, rather than quoting the larger number as if this slice produced it. - New section on the #4511 collision: the id was reserved with `pr_scan="degraded"` (no `gh` in this container, so the open-PR universe was never consulted), main then landed the usage-limit monitor as #4511, and `check:issue-ids:against-main` caught it at the pre-push hook. A degraded-scan reservation is provisional — re-check before pushing, not only before creating the file. Co-Authored-By: Claude <noreply@anthropic.com> ✓
1 task
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Docs-only. Lands the two architect specs for the 3.2× compiled-code program, plus the correctness bug their investigation surfaced.
#4405 — receiver-type specialisation (spec)
The spec re-scopes the issue: the whole-program
this-receiver inference it originally asked for is already built, sound, default-ON, and at 97.9 % coverage on acorn (488 typed twins, zero declines — measured, not assumed). Every soundness condition the brief asked to "specify precisely" is already implemented and is mapped to file:line in the spec, so a dev reading only the issue body would have rebuiltanalyzeProtoMethodWriteOnce.The real residual, measured: non-
thisreceivers at 4,064 asked → 244 proven (6.0 %) → 88 inlined, 156 proven-then-declined dominated bynofield:Node.*, and zero non-thiswrites inlined because no write-side emitter exists. Root cause of the 156:__fnctor_Nodederives slots from constructor-body writes only, so acorn's entire AST payload lives in the dynamic$residsidecar.Two design verdicts, both against the issue's original wording: per-site decline, not all-or-nothing (the shipped architecture is already per-site; all-or-nothing would regress a measured 97.9 %), and keep the
ref.testguard — an unguarded cast turns whole-program imprecision into a runtime trap with no fallback. The sound route to "guard-free" is hoisting one test per binding per function.#4406 — return-type unboxing ABI (spec)
Confirms #4405 §5's seam (
ctx.directCallTwinsalready keys"<F>/<m>" → {twinName, params, results};fillDirectCallTrampolinesalready degrades on signature mismatch) and corrects three premises: thebooleanFunctionNamesfixpoint already exists (inferBooleanFunctionNames, 83 names on acorn) and its result is discarded; all 83 are already swallowed intonumericFunctionNames; and the issue's__box_boolean < 100ktarget is unreachable via returns alone — the producer census showsthen_return = 0, i.e. there are no boxed-boolean returns left to remove. The AC is amended in-file rather than left as a target that would read as a null.#4414 — devirtualized prototype-method call returns a boolean as a number (bug, live on main)
("" + p.eat(5)).lengthanswers 1 instead of 4 on the standalone lane with default flags. Discriminated by measurement:"" + trueliteral,var b = (5===5), plainfunction eq(){}callP.prototype.eat = …; "" + p.eat(5)JS2WASM_NUMERIC_TWINS=0/JS2WASM_TYPED_THIS=0JS2WASM_DIRECT_CALLS=0The fix this issue originally proposed (an
isBooleanishveto on thenumericFunctionsfixpoint) was implemented and measured: the repro is byte-for-byte unchanged. It is therefore ruled out as the root cause and the issue is retitled to what the evidence supports — the result type chosen in the direct-call devirtualization fill path. acorn keeps checksum 422 only because its predicates are consumed exclusively in conditions, where an f64 0/1 and a boolean agree.Note on the id: filed first as #4407, which collided with
4407-react-dom-wasm-capturealready onmain(the allocation ran with a degraded open-PR scan, which warns about precisely this). Reallocated to #4414 viaclaim-issue --allocate.CLA
Generated by Claude Code