08:16
<Michael Ficarra>
FYI, if you haven't refreshed TCQ since yesterday, you should do so at some point (not all at once though please!)
08:17
<Christian Ulbrich>
IE and observers are also able to enter the queue, don't they?
08:17
<Michael Ficarra>
observers cannot
08:17
<Michael Ficarra>
they cannot contribute in any way
08:17
<Christian Ulbrich>
Okay, but IE can?
08:18
<ljharb>
yes
08:18
<Christian Ulbrich>
dumb question ofc.
08:18
<Christian Ulbrich>
sorry, mangaging notes answering observers...
08:25
<Christian Ulbrich>
Mark hits it right on the spot. There is very much deviation in equality.
08:29
<Justin Ridgewell>
These features 💯
08:30
<ljharb>
there's enough that there's no "one size fits all". but all the ones i've encountered can be pretty easily achieved with this proposal as-is
08:37
<Justin Ridgewell>
I have implemented recursion for node iterator work via iterators, and it was sooo much easier to reason about
08:45
<eemeli>
Michael Ficarra: On TCQ, how do I customize the bit in parentheses after by name?
08:46
<nicolo-ribaudo>
GitHub profile
08:46
<nicolo-ribaudo>
The "company" field
08:47
<eemeli>
Ah, got it.
08:50
<yusukesuzuki>
For DOM node tree, there is a API TreeWalker, https://developer.mozilla.org/en-US/docs/Web/API/TreeWalker but I think this is not so much used, and comparison etc. are written by hand, probably because of complexity of using this API and too many edge cases each client care.
08:51
<ljharb>
i think also because most people don't work directly with DOM nodes
08:51
<ljharb>
meaning, either they use a vdom solution or something from the jquery era. i think TreeWalker may not have existed back in the olden times when I worked with DOM nodes directly, so i never used it myself
08:52
<Christian Ulbrich>
yusukesuzuki: Fascinating. Back then, when I was dabbling with Lit, I used to do some direct DOM stuff, for my so-called structural mixins - custom elements that can attach (shared) behavior to other elements.
09:01
<Duncan MacGregor>
So the only way to implement equality in the presence of private fields seems like it would require cooperation from the classes.
09:04
<Michael Ficarra>
💯 @eemeli nailed it
09:05
<Richard Gibson>
eemeli: the first non-frontmatter of https://github.com/JakobJingleheimer/proposal-comparisons is "The Problem: Determine whether and/or how A and B deviate from each other". What more are you looking for?
09:06
<eemeli>
From what I understood of the answer given to me, the motivation is not "Determine whether and/or how A and B deviate from each other", but something like "Determining whether and/or how A and B deviate from each other is hard."
09:07
<eemeli>
And then the explainer & presentation talk about performance as their focus. And that's confusing.
09:07
<ljharb>
the problem space is "determine". the motivation is "because determining is hard"
09:08
<ljharb>
so i imagine the problem statement would be something akin to "we need to determine and determining is hard"
09:08
<Michael Ficarra>
also it seems like the implementers are all very confident that this proposal is not well-motivated by performance
09:08
<Richard Gibson>
I missed the presentation today, but there is no mention of performance at https://github.com/JakobJingleheimer/proposal-comparisons
09:09
<eemeli>
Richard Gibson: Fair; the explainer is not as much about performace as the slides/presentation.
09:10
<eemeli>
In the explainer, I get a performance vibe from the use cases, in particular state management/virtual DOM.
09:13
<Richard Gibson>
hmm, I guess, but that's in the sense that "deep comparison speeds up real software", not in the sense that "deep comparison itself should be faster"
09:15
<Olivier Flückiger>
So I asked gemini to write a deep equals...
09:15
<Olivier Flückiger>
function deepEquals(a, b, visited = new WeakMap()) {
  if (Object.is(a, b)) return true;

  if (a == null || b == null) return false;
  if (typeof a !== typeof b) return false;

  if (typeof a !== 'object' && typeof a !== 'function') return false;
  if (typeof b !== 'object' && typeof b !== 'function') return false;

  // If both are functions and Object.is(a, b) was false, they are distinct functions.
  if (typeof a === 'function') return false;

  // Cycle detection
  let aVisited = visited.get(a);
  if (aVisited && aVisited.has(b)) return true;
  if (!aVisited) {
    aVisited = new WeakSet();
    visited.set(a, aVisited);
  }
  aVisited.add(b);

  // Prototype check
  if (Reflect.getPrototypeOf(a) !== Reflect.getPrototypeOf(b)) return false;
  if (Object.isExtensible(a) !== Object.isExtensible(b)) return false;

  // Built-in specific comparisons
  if (a instanceof Number || a instanceof Boolean || a instanceof String || a instanceof Symbol || a instanceof BigInt) {
    if (!Object.is(a.valueOf(), b.valueOf())) return false;
  }

  if (a instanceof Promise || a instanceof WeakMap || a instanceof WeakSet || (typeof WeakRef !== 'undefined' && a instanceof WeakRef)) {
    return false;
  }

  if (a instanceof Date) {
    if (!Object.is(a.getTime(), b.getTime())) return false;
  }

  if (a instanceof RegExp) {
    if (a.source !== b.source || a.flags !== b.flags) return false;
  }

  if (a instanceof ArrayBuffer || (typeof SharedArrayBuffer !== 'undefined' && a instanceof SharedArrayBuffer)) {
    if (a.byteLength !== b.byteLength) return false;
    const viewA = new Uint8Array(a);
    const viewB = new Uint8Array(b);
    for (let i = 0; i < a.byteLength; i++) {
      if (viewA[i] !== viewB[i]) return false;
    }
  }

  if (a instanceof DataView) {
    if (a.byteLength !== b.byteLength) return false;
    const viewA = new Uint8Array(a.buffer, a.byteOffset, a.byteLength);
    const viewB = new Uint8Array(b.buffer, b.byteOffset, b.byteLength);
    for (let i = 0; i < a.byteLength; i++) {
      if (viewA[i] !== viewB[i]) return false;
    }
  }

  // Set comparison
  if (a instanceof Set) {
    if (a.size !== b.size) return false;
    const matchedB = new Set();
    for (const itemA of a) {
      let found = false;
      for (const itemB of b) {
        if (!matchedB.has(itemB) && deepEquals(itemA, itemB, visited)) {
          matchedB.add(itemB);
          found = true;
          break;
        }
      }
      if (!found) return false;
    }
  }

  // Map comparison
  if (a instanceof Map) {
    if (a.size !== b.size) return false;
    const matchedB = new Set();
    for (const [keyA, valA] of a) {
      let found = false;
      for (const [keyB, valB] of b) {
        if (!matchedB.has(keyB) && deepEquals(keyA, keyB, visited) && deepEquals(valA, valB, visited)) {
          matchedB.add(keyB);
          found = true;
          break;
        }
      }
      if (!found) return false;
    }
  }

  // Compare own properties (including symbols, non-enumerable properties, holey arrays, and descriptors)
  const keysA = Reflect.ownKeys(a);
  const keysB = Reflect.ownKeys(b);

  if (keysA.length !== keysB.length) return false;

  for (const key of keysA) {
    if (a instanceof Error && key === 'stack') continue; // Ignore stack traces in error comparison

    const descB = Object.getOwnPropertyDescriptor(b, key);
    if (!descB) return false;
    const descA = Object.getOwnPropertyDescriptor(a, key);

    if (descA.enumerable !== descB.enumerable) return false;
    if (descA.configurable !== descB.configurable) return false;
    if (descA.writable !== descB.writable) return false;
    if (Boolean(descA.get) !== Boolean(descB.get)) return false;
    if (Boolean(descA.set) !== Boolean(descB.set)) return false;

    if (descA.get) {
      if (!deepEquals(descA.get, descB.get, visited)) return false;
    } else {
      if (!deepEquals(a[key], b[key], visited)) return false;
    }
  }

  return true;
}
09:15
<Michael Ficarra>
yes, one of the major use-cases is testing (where execution time is not as important), but CI time is not costless
This sure sounds like there is an expectation that this is somehow a "hot" operation that the champions would like to make faster.
09:15
<Olivier Flückiger>
just to have a baseline of "how hard" is this for llms...
09:17
<Richard Gibson>
if (Object.isExtensible(a) !== Object.isExtensible(b)) return false is not behavior in any deepEquals that I've ever seen...
09:17
<Michael Ficarra>
we don't have a slides link for this topic?
09:17
<eemeli>
... thus far!
09:18
<Michael Ficarra>
apparently the LLM has!
09:18
<Richard Gibson>
I'm not disputing the claim about slides, just about the explainer
09:18
<ljharb>
lol i haven't either, but comparing integrity level is definitely a good call
09:18
<Olivier Flückiger>
I think I asked it to find counterexamples and then it came up with that
09:18
<Clément Pit-Claudel>
The regex comparison is missing lastIndex. Not sure if we care
09:19
<ljharb>
yep, that counts too
09:20
<Michael Ficarra>
as always, it depends on what the user means by "equal" in this context, and there's lots of examples on either side of this specific line
09:21
<ljharb>
sure. but anything that anyone cares about must be checked, so users who don't care can filter it out
09:21
<ljharb>
since otherwise, those who care have no way to get that visibility
09:21
<Richard Gibson>
what? Why?
09:21
<Michael Ficarra>
this seems like such a can of worms
09:21
<ljharb>
because it's an observable aspect of an object
09:22
<Clément Pit-Claudel>
Hmm I think I found a bug in the Firefox console while testing this
09:22
<Michael Ficarra>
object identity is an observable aspect of an object
09:22
<ljharb>
certainly that's the kneejerk reaction we all rightly have when actually diving into the myriad of ways that JS objects can differ :-)
09:22
<Olivier Flückiger>
apparently it is enumerable and thus covered by the fall-through case
09:22
<Duncan MacGregor>
So, I think although internally we might need to consider everything and then filter stuff out, the default should likely be what we think the common case should be. If not we'll have something that is technically correct but horrible to use.
09:22
<ljharb>
that is true. but that's the one thing that people must omit to do deep equality
09:23
<ljharb>
fair. that's totally reasonable as long as there's an option to get at everything
09:23
<Clément Pit-Claudel>
Sweet!
09:23
<Richard Gibson>
if (a instanceof Error && key === 'stack') continue; // Ignore stack traces in error comparison is also an interesting detail
09:25
<Richard Gibson>
overall, I would consider this a deepEquals that misses the point entirely because what people mean by "deeply equals" varies (and that's a big part of the problem space that proposal-comparisons is trying to address)
09:55
<rbuckton>
waldemar, Chris de Almeida, Richard Gibson: If there's any chance you are able to look over the spec text for \Z at https://github.com/tc39/proposal-regexp-buffer-boundaries/pull/21 before end of plenary, please let me know as that would let me clear the Stage 2.7 condition from Day 1.
09:57
<Olivier Flückiger>
yeah, that's kinda funny it would add that line
09:57
<Olivier Flückiger>
I wonder where that came frome.
09:58
<Olivier Flückiger>
Other details I can see how they were basically implied by my prompts.
09:58
<Olivier Flückiger>
But it looks like it wasn't that bad at writing a useful comparison.
10:41
<nicolo-ribaudo>
Chairs, can I get a continuation for "export all from" to ask for state 2.7 reviewers? If next time I present we go to stage 2 we might go to stage 2.7, as there are only major design questions (do we even change the existing syntax at all) and not really in-stage-2 minor questions
11:04
<Justin Ridgewell>
Done
11:05
<Aki>
FOSDEM slides mentioned earlier https://hosted.akiro.se/2026/FOSDEM/falsehoods-FOSDEM-belives-CRA.pdf
11:06
<Aki>
Today's slides (which will also be added to agenda and notes) https://hosted.akiro.se/2026/Ecma/TC39/Cyber%20Resilience%20Act%20primer.pdf
11:20
<Clément Pit-Claudel>
Responding to mark: JS has this fun property that r? and r| are not the same (consider ()? vs ()| on "")
11:32
<rbuckton>
Yet another reason to be wary of trailing empty disjunctions...
11:38
<snek>
I wish we could somehow steer people to `/lu` by default
11:39
<Luca Casonato>
I wish we could somehow steer people to `/lu` by default
"use very strict"
11:39
<snek>
.mjs2
11:54
<rbuckton>
\Z test262 tests are approved, so spec review is all that is remaining
11:54
<Justin Ridgewell>
Dmitry Makhnev: We had a random room join the call?
11:54
<Justin Ridgewell>
Are these JetBrains people?
11:54
<Dmitry Makhnev>
It could be folks from MPS
11:55
<Dmitry Makhnev>
I'll check
11:55
<Dmitry Makhnev>
https://github.com/tc39/Reflector/issues/578#issuecomment-4111115697
11:57
<Andrew Paprocki>
can the chosen runtime regex optimization path be cached "globally"?
11:58
<Dmitry Makhnev>
Justin Ridgewell: I verified. It's JetBrains people from MPS https://github.com/tc39/Reflector/issues/578#issuecomment-4111115697
11:58
<Dmitry Makhnev>
We expect a few more
11:58
<Andrew Paprocki>
regex opt rainbow tables?
12:13
<Clément Pit-Claudel>

Thanks again to everyone for the great feedback and discussion. For those curious to read more, the website of the Linden project is here: https://lin.den.re

I demoed to a few people this week the graphical debugger we built to navigate the ECMAScript regex semantics. Here's a permalink to that tricky example Aurèle demoed, and a demo of what happens when a non-linear engine tries to match a*a*b on aaaaaa (click the l flag to see what it looks like in a linear engine instead; dimmed nodes are skipped).

12:26
<canadahonk>
anyone know who asked in the Prague room for notes? i presume non-delegate?
12:27
<Aki>
Dmitry Makhnev: 👆🏻
12:33
<Dmitry Makhnev>
Yes, it was not a delegate. It was an observer from the JetBrains side. I’m really sorry for the questions coming from someone who isn’t a delegate from JetBrains. For the notes, if acceptable, you can use my (DJM) acronym for this question. Sorry again.
12:37
<canadahonk>
no worries! just wanted to check :)
13:14
<rbuckton>
one review in for \Z spec text, might be able to clear the "conditional" 2.7 advancement by EOD, and even stage 3 since tests are approved
13:25
<Aki>
keith_miller: did you have slides for Atomics.pause ?
13:27
<keith_miller>
I did not
13:52
<Olivier Flückiger>
I feel like the "ESM phase import interaction with shared structs" is missing a concrete proposal on how to actually do the shared behavior. I found it hard to think about this discussion since everything is basically hypothetical.
13:53
<Olivier Flückiger>
I know that there are some ideas floating around on how to do it. But I didn't find something in writing.
13:54
<Aki>
KAIST?
13:54
<rbuckton>
I need to write up the various facets of what we've discussed in the shared structs meetings and update the explainer and spec text. Part of wrapping up the current Explicit Resource Management proposal and buffer boundaries is to clear some time in my schedule to get back to it.
13:56
<guybedford>
Cloudflare may be able to host a US meeting, if folks are interested in an Austin trip
13:56
<ljharb>
ooh, austin's great
13:56
<ljharb>
(but i'd prefer a mexico one if that's an option)
13:56
<Aki>
Canada? Mexico?
13:56
<Aki>
😍
13:58
<guybedford>
Cloudflare Lisbon or London office are also options actually
13:59
<ljharb>
portugal would be awesome for a europe one; it's cheaper than london too
14:00
<Zb Tenerowicz (ZTZ/naugtur)>
If the meeting location (and lodging) is significantly cheaper, it offsets the travel burden
14:01
<ljharb>
portugal + new york + tokyo would be perfectly awesome imo, and relatively friendly timezone-wise
14:01
<Zb Tenerowicz (ZTZ/naugtur)>
NY travel+lodging > Portugal small town travel+lodging for US people probably
14:01
<Mathieu Hofman>
Yeah large city US (or EU) non flight travel costs are fairly high
14:02
<ljharb>
doesn't have to be a small town, even lisbon isn't that expensive
14:04
<Chris de Almeida>
Lisbon office too small. London is the offer we are pursuing w/ Cloudflare for 2027. please sync with James Snell
14:16
<James M Snell>
I'm following up this week. Waiting for a response back