@farm.js/react 0.1.0-beta.8 → 0.1.0-beta.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -42,7 +42,7 @@ definitions, while generated code uses the tree-shakable feature entry.
42
42
 
43
43
  The persisted production-size fixtures and regression gate live in
44
44
  [`RUNTIME_SIZE_RESULTS.md`](./RUNTIME_SIZE_RESULTS.md). The recorded direct-only runtime premium is
45
- 73.6% smaller than the complete compatibility runtime premium; the feature-heavy keyed benchmark
45
+ 82.6% smaller than the complete compatibility runtime premium; the feature-heavy keyed benchmark
46
46
  application removes 6,185 gzip bytes from its previous compiler-on build.
47
47
 
48
48
  For selective adoption, use annotation mode:
@@ -220,19 +220,27 @@ updates such as:
220
220
 
221
221
  ```tsx
222
222
  setItems((current) =>
223
- current.map((item) => (item.id === targetId ? { ...item, selected: !item.selected } : item)),
223
+ current
224
+ .map((item) => (item.id === targetId ? { ...item, label: nextLabel } : item))
225
+ .map((item) => (item.id === targetId ? { ...item, selected: !item.selected } : item)),
224
226
  );
225
227
  ```
226
228
 
227
- The generated native `map()` records which indexes returned new item identities. Farm then
228
- validates that length, keys, and positions are unchanged and patches only those row instances. The
229
- user's `map()` remains O(n); this removes the keyed runtime's second full key-and-binding scan.
230
- Queued hints compose. Key changes, structural edits, relevant mixed dependencies, and failed runtime
231
- checks use the existing complete reconciliation and LIS path. Non-functional setters, derived
232
- collections, block-bodied or mutating mappers, and other unproven forms are simply not hinted. No
233
- new option is required. A compiler report exposes the emitted-site count as
234
- `keyedMapUpdateHints`. The separate hint runtime capability is imported only when that count is
235
- nonzero, so direct-only and ordinary keyed builds do not retain it.
229
+ Farm executes every generated native `map()` and then compares the committed and final item
230
+ identities once. It validates final length, keys, and positions and patches each final changed row
231
+ once; intermediate arrays never receive DOM work. Every user `map()` remains O(n); this removes the
232
+ keyed runtime's second full key-and-binding scan. Queued hints compose. The source method lookup,
233
+ native result, callback order, and thrown errors are preserved.
234
+
235
+ Each stage requires an inline synchronous conditional mapper that returns the original item or an
236
+ object-spread replacement. An unsupported mapper anywhere in the chain disables the complete
237
+ setter hint. Custom methods still execute but record no metadata. Key changes, structural edits,
238
+ sparse or subclassed arrays, relevant mixed dependencies, and failed runtime checks use the
239
+ existing complete reconciliation and LIS path. Non-functional setters, derived collections,
240
+ block-bodied or mutating mappers, and other unproven forms are simply not hinted. No new option is
241
+ required. A compiler report counts prepared map calls as `keyedMapUpdateHints`. The separate hint
242
+ runtime capability is imported only when that count is nonzero, so direct-only and ordinary keyed
243
+ builds do not retain it.
236
244
 
237
245
  The same optional runtime recognizes conservative immutable appends on a direct keyed array:
238
246
 
@@ -250,52 +258,148 @@ reconciliation. A key that reads the collection prevents hint emission entirely.
250
258
  report exposes the emitted-site count as
251
259
  `keyedArrayAppendHints`.
252
260
 
261
+ Adjacent removal and append setters can share the same committed-row proof:
262
+
263
+ ```tsx
264
+ setItems((current) => current.filter((item) => item.id !== expiredId));
265
+ setItems((current) => [...current, incoming]);
266
+
267
+ setItems((current) => current.slice(start, end));
268
+ setItems((current) => [...current, ...incoming]);
269
+
270
+ setItems((current) => current.slice(start, end));
271
+ setItems((current) => [...current, incoming]);
272
+ setItems((current) =>
273
+ current.map((item) => (item.id === targetId ? { ...item, label: nextLabel } : item)),
274
+ );
275
+
276
+ setItems((current) => current.filter((item) => item.id !== expiredId));
277
+ setItems((current) =>
278
+ current.map((item) => (item.id === targetId ? { ...item, label: nextLabel } : item)),
279
+ );
280
+ setItems((current) => [...current, incoming]);
281
+ ```
282
+
283
+ The setters still execute in order and still create their normal native arrays. Before changing the
284
+ DOM, Farm validates the original committed token, every filter or slice survivor, the complete final
285
+ length, and every incoming key. It prepares all incoming keys, descriptors, bindings, and detached
286
+ host rows first; only then does it remove rejected rows, update survivor indexes, and append the new
287
+ suffix in one fragment. Existing survivors are neither rebound nor recreated, and additional
288
+ adjacent append setters are collapsed into the same final suffix. This keeps the unavoidable native
289
+ filter or slice work while removing the keyed runtime's second full scan.
290
+
291
+ One or more immediately adjacent safe same-key `map()` setters may run between the filter or slice
292
+ and the append, after the append, or in both positions. A safe map may also precede the structural
293
+ removal. Farm carries the original survivor indices or retained interval through those native maps
294
+ and records each replacement against its committed row. Before touching the DOM it validates the
295
+ complete dense result, every survivor identity, every changed key and binding, and every incoming
296
+ row. It then removes only rejected rows, patches only changed survivors, and creates the suffix from
297
+ its final values. The owner stays mounted, survivor DOM identity is preserved, and the suffix is
298
+ appended once.
299
+
300
+ Only concise updater results that form one direct chain for the same state array are linked. The row
301
+ and key must be compiler-owned and index-independent. A reorder in the structural-append chain, an
302
+ unsupported or non-adjacent map, an unhinted update to that state, another dirty row dependency,
303
+ collection-reading binding, custom, sparse, or subclassed array, nested or React-owned row,
304
+ duplicate final key, or reuse of any committed key in the appended suffix keeps complete React
305
+ reconciliation before a DOM write. A mapped survivor whose key changes also falls back before
306
+ mutation. No API or configuration is added. Compiler reports use the existing
307
+ `keyedArrayFilterHints`, `keyedArraySliceHints`, and `keyedArrayAppendHints` counts, and modules
308
+ without both accepted operations omit the composed runtime.
309
+
253
310
  The mirror-image prepend form is supported when the keyed row and key do not read the row index:
254
311
 
255
312
  ```tsx
256
313
  setItems((current) => [nextItem, ...current]);
257
314
  setItems((current) => [...nextItems, ...current]);
315
+
316
+ setItems((current) => current.filter((item) => item.id !== expiredId));
317
+ setItems((current) => [nextItem, ...current]);
318
+
319
+ setItems((current) => current.slice(start, end));
320
+ setItems((current) => [...nextItems, ...current]);
321
+
322
+ setItems((current) => current.filter((item) => item.id !== expiredId));
323
+ setItems((current) => [nextItem, ...current]);
324
+ setItems((current) =>
325
+ current.map((item) => (item.id === targetId ? { ...item, label: nextLabel } : item)),
326
+ );
327
+
328
+ setItems((current) => current.slice(start, end));
329
+ setItems((current) =>
330
+ current.map((item) => (item.id === targetId ? { ...item, label: nextLabel } : item)),
331
+ );
332
+ setItems((current) => [nextItem, ...current]);
258
333
  ```
259
334
 
260
335
  Farm validates the committed source and queued prepend chain, creates only the new prefix, inserts
261
336
  it before the first existing row, and shifts the stored indexes used by delegated row events.
262
- Existing row DOM and bindings stay in place. Index-aware rows, collection-reading bindings or
263
- keys, React-owned row structures, middle insertion, direct replacement, duplicate keys, custom or
264
- sparse arrays, and failed validation use complete keyed reconciliation. The compiler report
265
- exposes the emitted-site count as `keyedArrayPrependHints`.
266
-
267
- Literal native slices can carry their exact retained interval into the same removal runtime:
337
+ When an adjacent filter or bounded slice runs first, the compiler also carries the exact survivor
338
+ positions into the prepend. The runtime removes only rejected rows, preserves every surviving DOM
339
+ node, and creates only the final prefix instead of rescanning and rebinding the whole result.
340
+ Multiple adjacent prepends share the same proof.
341
+
342
+ One or more immediately adjacent safe same-key `map()` setters may run after the prepend or between
343
+ the removal and prepend. A safe map may also run immediately before the removal. Farm carries every
344
+ survivor back to its committed row, validates the complete dense result and every final key, then
345
+ patches only changed survivors and creates the prefix from its final mapped values. A surviving DOM
346
+ node keeps its identity even when its item object changes.
347
+
348
+ Index-aware rows, collection-reading bindings or keys, React-owned or nested row structures,
349
+ middle insertion, direct replacement, a reordered structural chain, an unsupported or non-adjacent
350
+ map, duplicate final keys, reuse of any committed key in the new prefix, custom or sparse arrays,
351
+ and failed validation use complete keyed reconciliation before any DOM mutation. A mapped survivor
352
+ whose key changes also falls back before mutation. The compiler report exposes the emitted-site
353
+ count as `keyedArrayPrependHints`; no option or component API is added, and modules without the
354
+ accepted removal, prepend, and map chain omit its mapped runtime.
355
+
356
+ Native slices with compiler-safe bounds can carry their exact retained interval into the same
357
+ removal runtime:
268
358
 
269
359
  ```tsx
270
360
  setItems((current) => current.slice(1_000));
271
361
  setItems((current) => current.slice(0, -1_000));
272
362
  setItems((current) => current.slice(2, 8));
363
+ setItems((current) => current.slice(trimCount));
364
+ setItems((current) => current.slice(visible.start, visible.end));
273
365
  ```
274
366
 
275
367
  For compiler-owned host rows whose render and key do not read the row index, Farm validates the
276
368
  committed source and queued slice chain, preserves every surviving DOM row, and removes only rows
277
369
  outside the retained interval. A slice-only chain does not reread surviving keys, descriptors, or
278
- bindings. One or two build-time safe-integer bounds are required. Runtime bounds, block-bodied or
279
- chained updates, custom slice methods, sparse or subclassed arrays, index-aware or
280
- collection-reading rows, React-owned structures, and failed validation keep complete keyed
281
- reconciliation. No option or component is added. The compiler report exposes the emitted-site
282
- count as `keyedArraySliceHints`.
370
+ bindings. One or two safe-integer literals or compiler-safe runtime expressions are required.
371
+ Identifiers, property reads, side-effect-free arithmetic and conditionals, and safe `Math` calls
372
+ are supported. Farm preserves native method lookup, argument evaluation, coercion, results, and
373
+ errors, then records metadata only when the evaluated bounds are already safe integers. Calls,
374
+ assignments, updates, unsafe evaluated bounds, block-bodied or chained updates, custom slice
375
+ methods, sparse or subclassed arrays, index-aware or collection-reading rows, React-owned
376
+ structures, and failed validation keep complete keyed reconciliation. No option or component is
377
+ added. The compiler report exposes the emitted-site count as `keyedArraySliceHints`.
283
378
 
284
379
  A fixed-size feed can combine that retained tail with a new keyed suffix:
285
380
 
286
381
  ```tsx
287
382
  setItems((current) => [...current.slice(1), nextItem]);
288
383
  setItems((current) => [...current.slice(1_000), ...nextItems]);
384
+
385
+ const trimCount = pageSize * pagesToExpire;
386
+ setItems((current) => [...current.slice(trimCount), ...nextItems]);
289
387
  ```
290
388
 
291
- Farm executes the ordinary native slice and array construction, then validates the committed
292
- source, retained item identities, and incoming keys. It removes only the expired prefix, leaves
293
- the retained DOM rows in place, and creates only the incoming suffix. This first form supports one
294
- build-time safe-integer slice bound and compiler-owned, index-independent host rows. Reused keys,
295
- block-bodied updaters, custom slice behavior, collection-reading or index-aware rows, nested or
296
- React-owned rows, queued uncommitted windows, and failed checks use complete keyed reconciliation.
297
- The optional all-hint runtime is selected only for modules that emit this optimization. Reports
298
- expose the site count as `keyedArrayRollingWindowHints`.
389
+ Farm executes the ordinary native slice and array construction, then validates the complete hint
390
+ chain back to the committed source, retained item identities, and final incoming keys. Multiple
391
+ rolling setters queued before one compiler flush collapse into one cumulative prefix removal; rows
392
+ introduced by an earlier setter are created only if they remain in the final suffix. Farm removes
393
+ only the expired committed prefix, leaves the retained DOM rows in place, and creates only that
394
+ final incoming suffix. This form supports one
395
+ safe-integer literal or compiler-safe runtime slice bound and compiler-owned, index-independent
396
+ host rows. Identifiers, property reads, side-effect-free arithmetic and conditionals, and safe
397
+ `Math` calls are supported while preserving native lookup, evaluation, results, and errors.
398
+ Effectful expressions, reused keys, block-bodied updaters, custom slice behavior,
399
+ collection-reading or index-aware rows, nested or React-owned rows, mixed or unhinted queued chains,
400
+ unsafe or no-op evaluated bounds, and failed checks use complete keyed reconciliation. The
401
+ optional all-hint runtime is selected only for modules that emit this optimization. Reports expose
402
+ the site count as `keyedArrayRollingWindowHints`.
299
403
 
300
404
  Native known-position updates can avoid a complete keyed scan too:
301
405
 
@@ -330,12 +434,13 @@ through one document fragment. It then removes only the replaced window. When th
330
434
  has the same length and the same keys in the same order, Farm prepares every binding read and
331
435
  changed DOM target across the complete window first, patches the existing rows in place, and
332
436
  updates the stored row objects used by later events. That path creates no descriptors or DOM rows,
333
- and preserves row identity, focus, and selection. A fixed-length window may instead reorder keys
334
- from inside its own removed interval and mix them with globally fresh keys. Farm prepares all
335
- reused binding updates, new descriptors, binding snapshots, and detached rows before the first DOM
336
- write. It removes only retired rows, preserves each reused row, batches adjacent new rows in a
337
- fragment, and applies LIS only to the reused part of that interval so it moves the fewest connected
338
- rows needed by the local permutation. Rows outside the interval are not rerendered or rebound.
437
+ and preserves row identity, focus, and selection. A window may instead grow or shrink while it
438
+ reorders keys from inside its own removed interval and mixes them with globally fresh keys. Farm
439
+ prepares all reused binding updates, new descriptors, binding snapshots, and detached rows before
440
+ the first DOM write. It removes only retired rows, preserves each reused row, batches adjacent new
441
+ rows in a fragment, updates shifted suffix indexes, and applies LIS only to the reused part of that
442
+ interval so it moves the fewest connected rows needed by the local permutation. Rows outside the
443
+ interval are not rerendered or rebound.
339
444
  Multiple length-preserving same-key windows
340
445
  queued before one compiler flush compose into one atomic refresh. Fixed-length queued windows may
341
446
  mix same-key refreshes with globally new final keys, and both disjoint and overlapping windows are
@@ -350,9 +455,8 @@ collection-reading rows, custom methods, position expressions with user calls or
350
455
  runtime positions that are not safe integers, dynamic, zero, negative, or fractional removal
351
456
  counts, other `toSpliced()` forms, block-bodied updaters, unsafe incoming expressions, queued
352
457
  chains containing a structural window or unhinted intermediate update, existing keys moved from
353
- outside the removed interval, length-changing partially reused windows, duplicate final keys,
354
- nested or React-owned rows, and failed checks use complete keyed reconciliation before the fast
355
- path mutates the DOM.
458
+ outside the removed interval, duplicate final keys, nested or React-owned rows, and failed checks
459
+ use complete keyed reconciliation before the fast path mutates the DOM.
356
460
  Reports expose the site count as `keyedArrayPositionHints`. Batch insertion and exact-window
357
461
  replacement use progressively separate optional runtime capabilities, so existing single-position
358
462
  and batch-only bundles do not retain window validation or replacement code.
@@ -364,14 +468,208 @@ setItems((current) => current.toReversed());
364
468
  ```
365
469
 
366
470
  Farm preserves the method lookup, call result, and errors, then records metadata only for the native
367
- method on a committed ordinary array. The runtime verifies equal lengths and every reversed item
368
- identity before moving the existing keyed elements with the minimum `n - 1` connected DOM moves.
369
- It does not reread row keys, descriptors, or bindings and does not run the generic LIS calculation.
370
- Index-aware or collection-reading rows, arguments, computed or chained calls, block-bodied
371
- updaters, custom methods, sparse or subclassed behavior, queued uncommitted reversals, nested or
372
- React-owned rows, and failed checks keep complete keyed reconciliation. Reports expose the site
373
- count as `keyedArrayReorderHints`, and modules without one omit the reorder runtime. Farm does not
374
- polyfill `Array.prototype.toReversed`.
471
+ method on an ordinary array whose chain starts at the committed collection. One direct reverse
472
+ verifies equal lengths and every reversed item identity before moving the existing keyed elements
473
+ with the minimum `n - 1` connected DOM moves. It does not reread row keys, descriptors, or bindings
474
+ and does not run the generic LIS calculation. Consecutive concise native `toReversed()` and
475
+ `toSorted()` setters queued before one flush compose into one final validated permutation. The
476
+ runtime skips intermediate DOM states. When the proven chain contains only reversals, Farm tracks
477
+ their parity relative to the committed rows: an even count validates exact identity and performs
478
+ no DOM moves, source-item map construction, or LIS; an odd count validates exact reverse and uses
479
+ the same minimum `n - 1` moves as one reverse. A chain containing a sort keeps the general final
480
+ permutation and uses LIS once. A single concise updater may also chain two or more native reorder
481
+ operations:
482
+
483
+ ```tsx
484
+ setItems((current) => current.toSorted((left, right) => left.rank - right.rank).toReversed());
485
+ ```
486
+
487
+ Farm evaluates every lookup and call in JavaScript order, carries the same committed token through
488
+ the pipeline, and reconciles only its final result. Index-aware or collection-reading rows,
489
+ arguments to `toReversed()`, referenced comparators, computed methods, block-bodied updaters, custom
490
+ methods, sparse or subclassed behavior, structural calls after reordering, an unhinted intermediate
491
+ update, nested or React-owned rows, and failed checks keep complete keyed reconciliation.
492
+
493
+ A compiler-safe `filter()` or bounded `slice()` prefix may precede the native reorder suffix:
494
+
495
+ ```tsx
496
+ setItems((current) =>
497
+ current
498
+ .filter((item) => item.visible)
499
+ .toSorted((left, right) => left.rank - right.rank)
500
+ .toReversed(),
501
+ );
502
+ ```
503
+
504
+ Farm validates the complete survivor set and final order before the first DOM write, removes only
505
+ rejected rows, and applies LIS once to the survivors. Concise filter/slice and reorder setters also
506
+ compose when queued in that order before one flush. Unsupported calls or a structural call after a
507
+ reorder fall back. Reports count each compiled step in the existing filter, slice, sort, or reverse
508
+ counter, and modules without those operations omit their optional runtimes. Farm does not polyfill
509
+ `Array.prototype.toReversed`.
510
+
511
+ A compiler-safe same-key map may also appear before or after native reorder steps:
512
+
513
+ ```tsx
514
+ setItems((current) =>
515
+ current
516
+ .map((item) => (item.id === editedId ? { ...item, label: nextLabel } : item))
517
+ .map((item) => (item.id === editedId ? { ...item, rank: nextRank } : item))
518
+ .toSorted((left, right) => left.rank - right.rank),
519
+ );
520
+ ```
521
+
522
+ Farm executes every native map and reorder call normally. For consecutive accepted maps, it checks
523
+ each native call but compares only the input and final result of that map segment, avoiding a full
524
+ lineage scan for every intermediate array. It verifies the committed token, dense-array shape, a
525
+ one-to-one source-item match, and every final replacement key before touching the DOM, then runs one
526
+ LIS and patches each changed row once. Unchanged rows need no second key or binding read. Queued
527
+ supported map-and-reorder setters compose against the same committed rows. Every accepted map
528
+ requires an inline synchronous conditional mapper that returns either the original item or an
529
+ object-spread replacement, plus index-independent compiler-owned host rows. Changed keys,
530
+ referenced or block-bodied callbacks, unconditional replacements, `thisArg`, structural calls in
531
+ the same chain, computed or custom methods, sparse or subclassed arrays, collection-reading
532
+ bindings, nested or React-owned rows, and failed checks use complete keyed reconciliation. Reports
533
+ use the existing map, sort, and reorder hint counters, and unrelated modules do not retain this
534
+ optional runtime.
535
+
536
+ The maps may also finish the concise pipeline:
537
+
538
+ ```tsx
539
+ setItems((current) =>
540
+ current
541
+ .toReversed()
542
+ .map((item) => (item.id === editedId ? { ...item, label: nextLabel } : item))
543
+ .map((item) => (item.id === editedId ? { ...item, rank: nextRank } : item)),
544
+ );
545
+ ```
546
+
547
+ Farm retains the preceding reorder instead of treating the mapped result as an unhinted snapshot.
548
+ An exact reverse uses the minimum-move reverse path without a general source-item lookup or LIS. A
549
+ sort remains an ambiguous permutation, so Farm performs one validated source lookup and LIS pass.
550
+ Safe maps on both sides of a reorder flatten their replacements back to the same committed rows.
551
+
552
+ Safe maps may also run before, between, or after index-independent `filter` or `slice` steps in one
553
+ concise functional setter. A final native reorder is optional:
554
+
555
+ ```tsx
556
+ setItems((current) =>
557
+ current
558
+ .filter((item) => item.visible)
559
+ .map((item) => (item.id === editedId ? { ...item, label: nextLabel } : item))
560
+ .slice(0, limit)
561
+ .toSorted((left, right) => left.rank - right.rank),
562
+ );
563
+
564
+ setItems((current) =>
565
+ current
566
+ .map((item) => (item.id === editedId ? { ...item, label: nextLabel } : item))
567
+ .filter((item) => item.visible)
568
+ .slice(0, limit),
569
+ );
570
+ ```
571
+
572
+ The structural helpers retain both the committed survivor indices and mapped-item sources across
573
+ each accepted step. The final commit removes rejected rows, performs LIS moves only when a reorder
574
+ needs them, and patches bindings only for changed survivors. Every native callback and method still
575
+ runs in JavaScript order.
576
+
577
+ The structural and map steps may also be split across immediately adjacent setter calls in either
578
+ order:
579
+
580
+ ```tsx
581
+ // Map, then structural work.
582
+ setItems((current) =>
583
+ current.map((item) => (item.id === editedId ? { ...item, label: nextLabel } : item)),
584
+ );
585
+ setItems((current) => current.filter((item) => item.visible));
586
+ setItems((current) => current.slice(0, limit));
587
+
588
+ // Structural work, then maps.
589
+ setItems((current) => current.filter((item) => item.visible));
590
+ setItems((current) => current.slice(0, limit));
591
+ setItems((current) =>
592
+ current.map((item) => (item.id === editedId ? { ...item, label: nextLabel } : item)),
593
+ );
594
+ setItems((current) =>
595
+ current.map((item) => (item.id === editedId ? { ...item, rank: nextRank } : item)),
596
+ );
597
+ ```
598
+
599
+ Farm links only consecutive calls to the same setter. A leading map retains its first committed
600
+ source through later structural work; a terminal map consumes the saved survivor lineage from the
601
+ preceding filter or slice. Multiple safe steps in either segment may share the proof, and mixed
602
+ map/structural/map sequences compose. Every result and key is validated before the queued commit
603
+ touches the DOM. An intervening statement, another setter, an unsafe callback, a changed key, or
604
+ failed runtime validation keeps complete keyed reconciliation.
605
+
606
+ The survivor proof may continue through adjacent native reorder setters:
607
+
608
+ ```tsx
609
+ setItems((current) => current.filter((item) => item.visible));
610
+ setItems((current) =>
611
+ current.map((item) => (item.id === editedId ? { ...item, rank: nextRank } : item)),
612
+ );
613
+ setItems((current) => current.toSorted((left, right) => left.rank - right.rank));
614
+ setItems((current) => current.toReversed());
615
+ ```
616
+
617
+ Farm retains the committed survivor positions and same-key replacements until the final queued
618
+ value. The commit removes rejected rows, patches changed survivors, and applies the final order in
619
+ one validated DOM transaction. Exact reverses use the minimum-move reverse path; an arbitrary sort
620
+ uses one source lookup and LIS. Non-adjacent calls, another setter, unsupported syntax, or a failed
621
+ shape/key check keep complete reconciliation.
622
+
623
+ The reorder and safe maps may also be adjacent setter calls in the same synchronous block:
624
+
625
+ ```tsx
626
+ setItems((current) => current.toReversed());
627
+ setItems((current) =>
628
+ current.map((item) => (item.id === editedId ? { ...item, label: nextLabel } : item)),
629
+ );
630
+ setItems((current) =>
631
+ current.map((item) => (item.id === editedId ? { ...item, rank: nextRank } : item)),
632
+ );
633
+ ```
634
+
635
+ The compiler links only consecutive calls to the same setter. It keeps the reorder token through
636
+ each accepted native map, then validates row keys before applying the same exact-reverse or
637
+ sort-permutation path at commit. Adjacent compiler-safe filter or slice work switches to the
638
+ structural proof above. An intervening statement, another setter, an unsupported map, or a changed
639
+ key keeps the ordinary complete fallback. Standalone map-only components do not retain the
640
+ map-and-reorder runtime.
641
+
642
+ The mirror order is supported as well: two or more adjacent concise same-key map setters may be
643
+ followed by a concise native reverse or sort setter. Farm records their replacement lineage from
644
+ the committed collection and carries it into the final reorder. Only adjacent calls to the same
645
+ setter are linked; intervening work and unsupported updates retain complete reconciliation.
646
+
647
+ Mapped lineage also continues through multiple adjacent native reorder setters. For example,
648
+ `map -> reverse -> sort -> reverse` keeps the same committed-row proof until the final value, then
649
+ performs one validated keyed reconciliation. A concise `map().toReversed()` pipeline may start the
650
+ same chain. Adjacent compiler-safe filter or slice work changes it into a structural chain while
651
+ retaining the committed source. Every updater and native method still executes in order; another
652
+ setter, intervening work, or an unsupported method ends the chain and preserves the complete
653
+ fallback.
654
+
655
+ A reverse before the safe map pipeline may be queued in a separate setter:
656
+
657
+ ```tsx
658
+ setItems((current) => current.toReversed());
659
+ setItems((current) =>
660
+ current.map((item) => (item.id === editedId ? { ...item, label: nextLabel } : item)).toReversed(),
661
+ );
662
+ ```
663
+
664
+ A direct `toReversed()` suffix is more specific than an arbitrary permutation. When all preceding
665
+ maps retain committed row order, Farm validates the mirrored source-to-result relation and every
666
+ changed binding before touching the DOM, then performs the minimum-move reverse without building a
667
+ second item lookup map or running LIS. Additional exact reversals toggle that proof between reverse
668
+ and identity. Therefore two reversals after safe maps patch changed rows in committed order without
669
+ moving DOM nodes or creating the generic source map; three use the exact reverse path. Exact reverse
670
+ metadata also composes across queued setters: a queued reverse followed by safe maps and another
671
+ reverse retains exact identity, so only changed row bindings are patched. A preceding sort or any
672
+ ambiguous order keeps the general permutation path.
375
673
 
376
674
  A direct native immutable sort can use the same optional reorder runtime:
377
675
 
@@ -382,15 +680,18 @@ setLabels((current) => current.toSorted());
382
680
 
383
681
  Farm recognizes a concise functional setter with no comparator or an inline synchronous comparator
384
682
  from the compiler-safe expression subset. It preserves the original method lookup, comparator,
385
- stable native result, and errors. After the native sort runs, the runtime validates a committed
386
- ordinary dense array, equal lengths, and a unique one-to-one item-identity permutation. It then
387
- uses LIS to move only `n - LIS` keyed DOM nodes without rereading row keys, descriptors, or
388
- bindings. The native sorting work itself is unchanged.
683
+ stable native result, and errors. After the native sort runs, the runtime validates an ordinary
684
+ dense array whose reorder chain starts at the committed collection, equal lengths, and a unique
685
+ one-to-one item-identity permutation. It then uses LIS to move only `n - LIS` keyed DOM nodes
686
+ without rereading row keys, descriptors, or bindings. Multiple concise native sorts and reverses
687
+ queued in one flush, or chained in one concise updater, share the original committed token and
688
+ reconcile only their final permutation. The native sorting work itself is unchanged.
389
689
 
390
690
  Index-aware or collection-reading rows, referenced comparators, block-bodied updaters, computed or
391
- chained calls, custom methods, sparse or subclassed arrays, duplicate item identities, queued
392
- uncommitted sorts, nested or React-owned rows, and failed checks keep complete keyed
393
- reconciliation. Reports expose the site count as `keyedArraySortHints`; sort shares the optional
691
+ unsupported chained calls, custom methods, sparse or subclassed arrays, duplicate item identities,
692
+ unhinted intermediate updates, structural calls after reordering, nested or React-owned rows, and
693
+ failed checks keep complete keyed reconciliation. A compiler-safe filter/slice prefix is supported.
694
+ Reports count each compiled sort step as a `keyedArraySortHints` entry; sort shares the optional
394
695
  reorder runtime, and Farm does not polyfill `Array.prototype.toSorted`.
395
696
 
396
697
  Concise immutable filters on a direct keyed array can carry removal positions into the same
@@ -690,19 +991,21 @@ reasons aggregated by count. Its summary and per-module `optimizations` also rep
690
991
  `keyedMapLookupTargets`, the number of native-Map keyed lookup bindings;
691
992
  `keyedMembershipTargets`, the number of native-Set membership bindings;
692
993
  `keyedCollectionUpdateHints`, the number of compiler-proven native Set/Map mutation sites; and
693
- `keyedMapUpdateHints`, the number of compiler-proven direct keyed `map()` update sites; and
994
+ `keyedMapUpdateHints`, the number of compiler-proven keyed `map()` update calls; and
694
995
  `keyedArrayAppendHints`, the number of compiler-proven direct keyed-array append sites; and
695
- `keyedArrayFilterHints`, the number of compiler-proven direct keyed-array filter sites; and
996
+ `keyedArrayFilterHints`, the number of compiler-proven keyed-array filter sites, including supported
997
+ structural reorder pipelines; and
696
998
  `keyedArrayPrependHints`, the number of compiler-proven direct keyed-array prepend sites; and
697
999
  `keyedArrayPositionHints`, the number of compiler-proven native exact-position insertion, single or
698
1000
  contiguous-range removal, single-row replacement, or exact-window replacement sites, including
699
1001
  guarded compiler-safe runtime positions;
700
1002
  and
701
- `keyedArrayReorderHints`, the number of compiler-proven direct native keyed-array reverse sites; and
702
- `keyedArraySortHints`, the number of compiler-proven direct native keyed-array sort sites; and
1003
+ `keyedArrayReorderHints`, the number of compiler-proven native keyed-array reverse steps; and
1004
+ `keyedArraySortHints`, the number of compiler-proven native keyed-array sort steps; and
703
1005
  `keyedArrayRollingWindowHints`, the number of compiler-proven retained-tail plus incoming-suffix
704
1006
  sites; and
705
- `keyedArraySliceHints`, the number of compiler-proven direct keyed-array slice sites. A custom
1007
+ `keyedArraySliceHints`, the number of compiler-proven keyed-array slice sites with literal or guarded
1008
+ compiler-safe runtime bounds, including supported structural reorder pipelines. A custom
706
1009
  project-relative `reportFile` also enables reporting.
707
1010
 
708
1011
  The runtime test compares the same counter interaction on both paths: ordinary React performs a
@@ -711,9 +1014,9 @@ commit and updates its two bindings directly. This is a deterministic structural
711
1014
  assertion; it is not presented as a cross-machine timing benchmark.
712
1015
 
713
1016
  Application and prototype calls, dynamic style objects, handlers outside JSX events, nested,
714
- computed, and rest props patterns, async handlers, unkeyed or index-keyed lists, chained maps,
715
- unsupported conditional roots, effects, and more advanced hook support intentionally stay on React
716
- in this release. Compiler-owned keyed rows support either one dedicated host-only map/`List` or
1017
+ computed, and rest props patterns, async handlers, unkeyed or index-keyed lists, unsupported map
1018
+ chains, unsupported conditional roots, effects, and more advanced hook support intentionally stay
1019
+ on React in this release. Compiler-owned keyed rows support either one dedicated host-only map/`List` or
717
1020
  one or more non-interactive ranges in a nested or component-root host container. A dedicated
718
1021
  non-interactive row may also contain multiple recursive logical or ternary host branches beside
719
1022
  stateful static host siblings, plus recursively nested non-interactive keyed ranges scoped by every