@bldrs-ai/conway 1.535.1506 → 1.536.1507

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.
@@ -30,7 +30,7 @@ var import_node_process = require("node:process");
30
30
  var readline = __toESM(require("node:readline"), 1);
31
31
 
32
32
  // compiled/src/version/version.js
33
- var versionString = "Conway v1.535.1506";
33
+ var versionString = "Conway v1.536.1507";
34
34
 
35
35
  // compiled/dependencies/conway-geom/interface/conway_geometry.js
36
36
  var wasmType = "";
@@ -14965,7 +14965,7 @@ ${t5.join("\n")}` : "";
14965
14965
  var import_process = require("process");
14966
14966
 
14967
14967
  // compiled/src/version/version.js
14968
- var versionString = "Conway v1.535.1506";
14968
+ var versionString = "Conway v1.536.1507";
14969
14969
 
14970
14970
  // compiled/dependencies/conway-geom/interface/conway_geometry.js
14971
14971
  function pThreadsAllowed() {
@@ -15943,7 +15943,7 @@ var ParsingBuffer = class {
15943
15943
  };
15944
15944
 
15945
15945
  // compiled/src/version/version.js
15946
- var versionString = "Conway v1.535.1506";
15946
+ var versionString = "Conway v1.536.1507";
15947
15947
 
15948
15948
  // compiled/dependencies/conway-geom/interface/conway_geometry.js
15949
15949
  function pThreadsAllowed() {
@@ -944,7 +944,7 @@ var EntityTypesIfcCount = 909;
944
944
  var entity_types_ifc_gen_default = EntityTypesIfc;
945
945
 
946
946
  // compiled/src/version/version.js
947
- var versionString = "Conway v1.535.1506";
947
+ var versionString = "Conway v1.536.1507";
948
948
 
949
949
  // compiled/dependencies/conway-geom/interface/conway_geometry.js
950
950
  var wasmType = "";
@@ -466,6 +466,31 @@ export declare class IfcAPI {
466
466
  budgetBytes: number;
467
467
  liveBytes: number;
468
468
  } | undefined;
469
+ /**
470
+ * Conway extension (M3): extract only one shard of a deferred model's
471
+ * geometry, so N workers — each with its own instance and heap — can pump
472
+ * disjoint products with no scheduling channel between them.
473
+ *
474
+ * Placement is a pure function of the product (its representation's mapped
475
+ * source), so every worker independently agrees on who owns what, and
476
+ * products sharing geometry land together rather than each shard rebuilding
477
+ * it. Measured at N=4: +0 % extra assets on MB-Khaya and +38.1 % on D3D
478
+ * against round-robin's +25 % and +40.7 %, for 1.76x and 2.34x wall-clock.
479
+ *
480
+ * **A shard is a SUBSET of the model.** Pumping one to completion yields
481
+ * part of the geometry; the consumer unions the shards. Call before the
482
+ * first ExtractGeometryBatch — after that the worklists exist and narrowing
483
+ * them would drop products already reported as pending, so it throws.
484
+ *
485
+ * @param modelID handle from a DEFER_GEOMETRY open
486
+ * @param shard `{index, count}`, or omitted for the whole model
487
+ * @return {boolean} false for unknown models and for passthroughs with no
488
+ * demand worklists (AP214/STEP), which cannot shard
489
+ */
490
+ SetGeometryShard(modelID: number, shard?: {
491
+ index: number;
492
+ count: number;
493
+ }): boolean;
469
494
  ExtractGeometryBatch(modelID: number, batchSize: number, meshCallback?: (mesh: FlatMesh) => void): {
470
495
  extracted: number;
471
496
  remaining: number;
@@ -1 +1 @@
1
- {"version":3,"file":"ifc_api.d.ts","sourceRoot":"","sources":["../../../../src/compat/web-ifc/ifc_api.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ifc_api.d.ts","sourceRoot":"","sources":["../../../../src/compat/web-ifc/ifc_api.ts"],"names":[],"mappings":"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"}
@@ -653,6 +653,35 @@ export class IfcAPI {
653
653
  }
654
654
  return result.setGeometryBudget(megabytes * BYTES_PER_MIB);
655
655
  }
656
+ /**
657
+ * Conway extension (M3): extract only one shard of a deferred model's
658
+ * geometry, so N workers — each with its own instance and heap — can pump
659
+ * disjoint products with no scheduling channel between them.
660
+ *
661
+ * Placement is a pure function of the product (its representation's mapped
662
+ * source), so every worker independently agrees on who owns what, and
663
+ * products sharing geometry land together rather than each shard rebuilding
664
+ * it. Measured at N=4: +0 % extra assets on MB-Khaya and +38.1 % on D3D
665
+ * against round-robin's +25 % and +40.7 %, for 1.76x and 2.34x wall-clock.
666
+ *
667
+ * **A shard is a SUBSET of the model.** Pumping one to completion yields
668
+ * part of the geometry; the consumer unions the shards. Call before the
669
+ * first ExtractGeometryBatch — after that the worklists exist and narrowing
670
+ * them would drop products already reported as pending, so it throws.
671
+ *
672
+ * @param modelID handle from a DEFER_GEOMETRY open
673
+ * @param shard `{index, count}`, or omitted for the whole model
674
+ * @return {boolean} false for unknown models and for passthroughs with no
675
+ * demand worklists (AP214/STEP), which cannot shard
676
+ */
677
+ SetGeometryShard(modelID, shard) {
678
+ const result = this.models.get(modelID);
679
+ if (result?.setGeometryShard === void 0) {
680
+ return false;
681
+ }
682
+ result.setGeometryShard(shard);
683
+ return true;
684
+ }
656
685
  ExtractGeometryBatch(modelID, batchSize, meshCallback) {
657
686
  const result = this.models.get(modelID);
658
687
  if (result?.extractGeometryBatch === void 0) {
@@ -9,6 +9,25 @@ import * as fs from "fs";
9
9
  import { beforeAll, describe, expect, test } from "@jest/globals";
10
10
  import { IfcAPI } from "./ifc_api.js";
11
11
  const SETTINGS = { COORDINATE_TO_ORIGIN: true, USE_FAST_BOOLS: true };
12
+ // Sharding refuses COORDINATE_TO_ORIGIN — each shard would derive its own
13
+ // recentre anchor — so every sharded open here goes without it.
14
+ const SHARD_SETTINGS = { COORDINATE_TO_ORIGIN: false, USE_FAST_BOOLS: true, DEFER_GEOMETRY: true };
15
+ /**
16
+ * A transform's exact bytes, as a comparable string.
17
+ *
18
+ * Rounding would make these comparisons unable to fail: a transform that
19
+ * moved by less than half the last printed digit would serialize identically
20
+ * to the one it is being checked against. Every use below is asserting that
21
+ * two paths produce the SAME output, so the encoding has to be lossless.
22
+ *
23
+ * @param transform The flat transformation.
24
+ * @return {string} A lossless encoding of every component.
25
+ */
26
+ function transformKey(transform) {
27
+ const exact = new Float64Array(transform);
28
+ return Buffer.from(exact.buffer, exact.byteOffset, exact.byteLength)
29
+ .toString("base64");
30
+ }
12
31
  let api;
13
32
  let buffer;
14
33
  /**
@@ -299,8 +318,7 @@ describe("OpenModelStreamed + DEFER_GEOMETRY", () => {
299
318
  api5.StreamAllMeshes(classicID, (mesh) => {
300
319
  for (let where = 0; where < mesh.geometries.size(); ++where) {
301
320
  const placed = mesh.geometries.get(where);
302
- classicPlacements.push(`${placed.geometryExpressID}@${[...placed.flatTransformation]
303
- .map((value) => value.toFixed(3)).join(",")}`);
321
+ classicPlacements.push(`${placed.geometryExpressID}@${transformKey(placed.flatTransformation)}`);
304
322
  }
305
323
  });
306
324
  const deferredID = await api5.OpenModelStreamed(fixture, { ...SETTINGS, DEFER_GEOMETRY: true });
@@ -310,8 +328,7 @@ describe("OpenModelStreamed + DEFER_GEOMETRY", () => {
310
328
  const { extracted, remaining } = api5.ExtractGeometryBatch(deferredID, 4, (mesh) => {
311
329
  for (let where = 0; where < mesh.geometries.size(); ++where) {
312
330
  const placed = mesh.geometries.get(where);
313
- pumpedPlacements.push(`${placed.geometryExpressID}@${[...placed.flatTransformation]
314
- .map((value) => value.toFixed(3)).join(",")}`);
331
+ pumpedPlacements.push(`${placed.geometryExpressID}@${transformKey(placed.flatTransformation)}`);
315
332
  }
316
333
  });
317
334
  ++batches;
@@ -415,8 +432,7 @@ describe("OpenModelStreamed + DEFER_GEOMETRY", () => {
415
432
  api6.StreamAllMeshes(classicID, (mesh) => {
416
433
  for (let where = 0; where < mesh.geometries.size(); ++where) {
417
434
  const placed = mesh.geometries.get(where);
418
- classicPlacements.push(`${placed.geometryExpressID}@${[...placed.flatTransformation]
419
- .map((value) => value.toFixed(3)).join(",")}`);
435
+ classicPlacements.push(`${placed.geometryExpressID}@${transformKey(placed.flatTransformation)}`);
420
436
  }
421
437
  });
422
438
  const deferredID = await api6.OpenModelStreamed(fixture, { ...SETTINGS, DEFER_GEOMETRY: true });
@@ -431,8 +447,7 @@ describe("OpenModelStreamed + DEFER_GEOMETRY", () => {
431
447
  const { extracted, remaining } = api6.ExtractGeometryBatch(deferredID, 4, (mesh) => {
432
448
  for (let where = 0; where < mesh.geometries.size(); ++where) {
433
449
  const placed = mesh.geometries.get(where);
434
- pumped.push(`${placed.geometryExpressID}@${[...placed.flatTransformation]
435
- .map((value) => value.toFixed(3)).join(",")}`);
450
+ pumped.push(`${placed.geometryExpressID}@${transformKey(placed.flatTransformation)}`);
436
451
  }
437
452
  });
438
453
  if (remaining === 0 && extracted === 0) {
@@ -580,6 +595,351 @@ describe("OpenModelStreamed + DEFER_GEOMETRY", () => {
580
595
  }
581
596
  api7.CloseModel(modelID);
582
597
  }, 240000);
598
+ test("shards partition the model: every instance exactly once", async () => {
599
+ // The property a worker pool rests on. Four instances each claim a shard
600
+ // and pump to completion; the union must equal what one unsharded load
601
+ // delivers — no instance lost, none built twice. Placement being a pure
602
+ // function of the product is what lets the shards agree without talking
603
+ // to each other, so this also pins that: the same product must land in
604
+ // the same shard from four independent decisions.
605
+ // Both fixtures deliberately: the mapped one exercises the product
606
+ // worklist, and aggregate_master_voids the rel-aggregates pass, which is
607
+ // a SEPARATE worklist with its own filter. Sharding one and not the other
608
+ // duplicates every aggregate across every shard — and on an
609
+ // assembly-heavy model that pass is most of the geometry, so this is the
610
+ // failure with real consequences, not the exotic one.
611
+ for (const fixturePath of [
612
+ "data/mapped_shared_representation.ifc",
613
+ "data/aggregate_master_voids.ifc",
614
+ ]) {
615
+ await partitionsExactlyOnce(fixturePath);
616
+ }
617
+ }, 240000);
618
+ /**
619
+ * Assert that N shards of a model union to exactly what one unsharded load
620
+ * delivers.
621
+ *
622
+ * @param fixturePath The model to check.
623
+ */
624
+ async function partitionsExactlyOnce(fixturePath) {
625
+ const fixture = new Uint8Array(fs.readFileSync(fixturePath));
626
+ const wholeApi = new IfcAPI();
627
+ await wholeApi.Init();
628
+ const wholeID = await wholeApi.OpenModelStreamed(fixture, SHARD_SETTINGS);
629
+ const whole = [];
630
+ for (;;) {
631
+ const { extracted, remaining } = wholeApi.ExtractGeometryBatch(wholeID, 4, (mesh) => {
632
+ for (let where = 0; where < mesh.geometries.size(); ++where) {
633
+ const placed = mesh.geometries.get(where);
634
+ whole.push(`${placed.geometryExpressID}@${transformKey(placed.flatTransformation)}`);
635
+ }
636
+ });
637
+ if (remaining === 0 && extracted === 0) {
638
+ break;
639
+ }
640
+ }
641
+ expect(whole.length).toBeGreaterThan(0);
642
+ const shardCount = 4;
643
+ const sharded = [];
644
+ const perShard = [];
645
+ for (let index = 0; index < shardCount; ++index) {
646
+ const api = new IfcAPI();
647
+ await api.Init();
648
+ const modelID = await api.OpenModelStreamed(fixture, SHARD_SETTINGS);
649
+ expect(api.SetGeometryShard(modelID, { index, count: shardCount }))
650
+ .toBe(true);
651
+ let delivered = 0;
652
+ for (;;) {
653
+ const { extracted, remaining } = api.ExtractGeometryBatch(modelID, 4, (mesh) => {
654
+ for (let where = 0; where < mesh.geometries.size(); ++where) {
655
+ const placed = mesh.geometries.get(where);
656
+ sharded.push(`${placed.geometryExpressID}@${transformKey(placed.flatTransformation)}`);
657
+ ++delivered;
658
+ }
659
+ });
660
+ if (remaining === 0 && extracted === 0) {
661
+ break;
662
+ }
663
+ }
664
+ perShard.push(delivered);
665
+ api.CloseModel(modelID);
666
+ }
667
+ // The union is the model: same multiset, nothing lost or doubled.
668
+ expect(sharded.slice().sort()).toEqual(whole.slice().sort());
669
+ // ...and no shard delivered the whole thing, which the equality above
670
+ // would happily accept from one shard doing everything. A single-instance
671
+ // model legitimately lands in one shard, so this only asserts that no
672
+ // shard exceeded the total.
673
+ expect(Math.max(...perShard)).toBeLessThanOrEqual(whole.length);
674
+ wholeApi.CloseModel(wholeID);
675
+ }
676
+ test("a shard cannot be claimed after pumping starts", async () => {
677
+ // Narrowing the worklists mid-load would drop products already reported
678
+ // as pending, so the model would quietly deliver less than it promised.
679
+ const api = new IfcAPI();
680
+ await api.Init();
681
+ const modelID = await api.OpenModelStreamed(new Uint8Array(fs.readFileSync("data/mapped_shared_representation.ifc")), { COORDINATE_TO_ORIGIN: false, USE_FAST_BOOLS: true, DEFER_GEOMETRY: true });
682
+ api.ExtractGeometryBatch(modelID, 1);
683
+ expect(() => api.SetGeometryShard(modelID, { index: 0, count: 2 }))
684
+ .toThrow(/before the first/);
685
+ api.CloseModel(modelID);
686
+ }, 240000);
687
+ test("enabling COORDINATE_TO_ORIGIN after claiming a shard is refused", async () => {
688
+ // The claim-time check alone is not enforcement: the proxy holds the
689
+ // CALLER'S settings object by reference and reads COORDINATE_TO_ORIGIN
690
+ // live when it derives the recentre frame. A caller that opens without
691
+ // it, claims a shard, then flips the flag would get per-shard anchors —
692
+ // subsets of a large-coordinate model shifted by whole grid cells,
693
+ // which no union-of-placements check catches on a fixture at the origin.
694
+ const api = new IfcAPI();
695
+ await api.Init();
696
+ const settings = { COORDINATE_TO_ORIGIN: false, USE_FAST_BOOLS: true, DEFER_GEOMETRY: true };
697
+ const modelID = await api.OpenModelStreamed(new Uint8Array(fs.readFileSync("data/mapped_shared_representation.ifc")), settings);
698
+ expect(api.SetGeometryShard(modelID, { index: 0, count: 2 })).toBe(true);
699
+ settings.COORDINATE_TO_ORIGIN = true;
700
+ expect(() => api.ExtractGeometryBatch(modelID, 1))
701
+ .toThrow(/COORDINATE_TO_ORIGIN was enabled on a sharded model/);
702
+ // The async entry is a SEPARATE path — on an external source it never
703
+ // reaches pumpGeometryBatch_ at all — so the guard has to hold there
704
+ // independently. It was bypassed when the check lived in the pump.
705
+ await expect(api.ExtractGeometryBatchAsync(modelID, 1))
706
+ .rejects.toThrow(/COORDINATE_TO_ORIGIN was enabled on a sharded model/);
707
+ api.CloseModel(modelID);
708
+ }, 240000);
709
+ test("a one-worker claim is accepted, whatever the model settings", async () => {
710
+ // {index: 0, count: 1} IS the unsharded model, and a coordinator
711
+ // that calls this uniformly for its N=1 baseline is doing nothing
712
+ // that needs cross-worker agreement. The guards below it exist only
713
+ // because workers must agree with each other, so applying them to a
714
+ // single worker would fail a configuration equivalent to never
715
+ // having claimed at all — including on a recentred model, which is
716
+ // how Share opens.
717
+ const api = new IfcAPI();
718
+ await api.Init();
719
+ const modelID = await api.OpenModelStreamed(new Uint8Array(fs.readFileSync("data/index.ifc")), { COORDINATE_TO_ORIGIN: true, USE_FAST_BOOLS: true, DEFER_GEOMETRY: true });
720
+ expect(api.SetGeometryShard(modelID, { index: 0, count: 1 }))
721
+ .toBe(true);
722
+ let delivered = 0;
723
+ for (;;) {
724
+ const { extracted, remaining } = api.ExtractGeometryBatch(modelID, 4, (mesh) => {
725
+ delivered += mesh.geometries.size();
726
+ });
727
+ if (remaining === 0 && extracted === 0) {
728
+ break;
729
+ }
730
+ }
731
+ // The whole model, not a subset, and no throw from the recentre
732
+ // guard on the pump either.
733
+ expect(delivered).toBeGreaterThan(0);
734
+ api.CloseModel(modelID);
735
+ }, 240000);
736
+ test("a malformed descriptor is reported as malformed", async () => {
737
+ // Validation runs before the incompatibility checks, so a bad
738
+ // descriptor on a recentred model says what is bad about it rather
739
+ // than blaming whichever guard it trips first.
740
+ const api = new IfcAPI();
741
+ await api.Init();
742
+ const modelID = await api.OpenModelStreamed(new Uint8Array(fs.readFileSync("data/index.ifc")), { COORDINATE_TO_ORIGIN: true, USE_FAST_BOOLS: true, DEFER_GEOMETRY: true });
743
+ expect(() => api.SetGeometryShard(modelID, { index: 3, count: 2 }))
744
+ .toThrow(/invalid shard/);
745
+ api.CloseModel(modelID);
746
+ }, 240000);
747
+ test("a model that already adopted a recentre frame cannot be sharded", async () => {
748
+ // WHITE-BOX, and deliberately so. The reported route here is
749
+ // ON_PREVIEW_MESH: the preview channel can install a coordination
750
+ // frame at OPEN, before any pump, after which a caller may set
751
+ // COORDINATE_TO_ORIGIN false on its own settings object and claim a
752
+ // shard — passing a flag-only guard while already sitting in a
753
+ // frame derived from whichever geometry THIS instance previewed.
754
+ //
755
+ // I could not get the preview channel to install a frame from a
756
+ // test (tried index.ifc and index_georeferenced.ifc; demandCoordination_
757
+ // stayed undefined), so this pins the guard on the state itself
758
+ // rather than pretending to reproduce the route to it. If the route
759
+ // is unreachable the guard is merely cheap; if it is reachable, this
760
+ // is what stops it.
761
+ const api = new IfcAPI();
762
+ await api.Init();
763
+ const modelID = await api.OpenModelStreamed(new Uint8Array(fs.readFileSync("data/index.ifc")), SHARD_SETTINGS);
764
+ const passthrough = api.getPassthrough(modelID);
765
+ // A frame adopted from somewhere other than the current flag.
766
+ passthrough.demandCoordination_ =
767
+ [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1000, 2000, 3000, 1];
768
+ expect(() => api.SetGeometryShard(modelID, { index: 0, count: 2 }))
769
+ .toThrow(/already adopted a recentre frame/);
770
+ api.CloseModel(modelID);
771
+ }, 240000);
772
+ test("a sharded model does not recentre even if a callback enables it", async () => {
773
+ // The window codex found in round 9: ON_PROGRESS is invoked
774
+ // synchronously from beginPhase, INSIDE the first pump — after the
775
+ // precondition check for that batch has passed and before the
776
+ // capture reads the flag. A handler enabling COORDINATE_TO_ORIGIN
777
+ // there would have each worker derive its own frame despite the
778
+ // guard.
779
+ //
780
+ // Two windows of this shape were patched individually in earlier
781
+ // rounds, so this asserts BOTH halves of closing the class:
782
+ // 1. geometry delivered inside the window is not recentred, and
783
+ // 2. the refusal still fires on the next batch, so the caller is
784
+ // told rather than quietly given a subset it cannot merge.
785
+ const api = new IfcAPI();
786
+ await api.Init();
787
+ const settings = {
788
+ COORDINATE_TO_ORIGIN: false,
789
+ USE_FAST_BOOLS: true,
790
+ DEFER_GEOMETRY: true,
791
+ // Only once the GEOMETRY phase begins — inside the first pump,
792
+ // after the shard was claimed. Flipping it earlier is caught by
793
+ // the claim-time refusal, which is correct and not this window.
794
+ ON_PROGRESS: (event) => {
795
+ if (event.phase === "geometry") {
796
+ settings.COORDINATE_TO_ORIGIN = true;
797
+ }
798
+ },
799
+ };
800
+ const modelID = await api.OpenModelStreamed(new Uint8Array(fs.readFileSync("data/index.ifc")), settings);
801
+ expect(api.SetGeometryShard(modelID, { index: 0, count: 2 }))
802
+ .toBe(true);
803
+ const windowed = [];
804
+ api.ExtractGeometryBatch(modelID, 4, (mesh) => {
805
+ for (let where = 0; where < mesh.geometries.size(); ++where) {
806
+ windowed.push(transformKey(mesh.geometries.get(where).flatTransformation));
807
+ }
808
+ });
809
+ // The handler really did flip it, mid-pump.
810
+ expect(settings.COORDINATE_TO_ORIGIN).toBe(true);
811
+ // (2) The refusal fires now that the flag is observable.
812
+ expect(() => api.ExtractGeometryBatch(modelID, 4))
813
+ .toThrow(/COORDINATE_TO_ORIGIN was enabled on a sharded model/);
814
+ // (1) ...and nothing delivered inside the window was recentred:
815
+ // identical to a shard whose flag was never touched. A derived
816
+ // frame would move every transform.
817
+ const referenceApi = new IfcAPI();
818
+ await referenceApi.Init();
819
+ const referenceID = await referenceApi.OpenModelStreamed(new Uint8Array(fs.readFileSync("data/index.ifc")), SHARD_SETTINGS);
820
+ referenceApi.SetGeometryShard(referenceID, { index: 0, count: 2 });
821
+ const reference = [];
822
+ referenceApi.ExtractGeometryBatch(referenceID, 4, (mesh) => {
823
+ for (let where = 0; where < mesh.geometries.size(); ++where) {
824
+ reference.push(transformKey(mesh.geometries.get(where).flatTransformation));
825
+ }
826
+ });
827
+ expect(reference.length).toBeGreaterThan(0);
828
+ expect(windowed).toEqual(reference);
829
+ api.CloseModel(modelID);
830
+ referenceApi.CloseModel(referenceID);
831
+ }, 240000);
832
+ test("a model opened with ON_PREVIEW_MESH cannot be sharded", async () => {
833
+ // The preview channel runs during OPEN, before a shard can be claimed,
834
+ // so its payloads are never partitioned: every worker in a pool would
835
+ // perform the same capped preview extraction and emit the same
836
+ // imposters, and a consumer forwarding those callbacks would receive N
837
+ // overlapping copies while only the durable pump was split.
838
+ //
839
+ // Note this is NOT covered by the adopted-frame guard: that one keys on
840
+ // demandCoordination_, which the preview only installs when recentring
841
+ // is on. With COORDINATE_TO_ORIGIN false there is no frame to catch,
842
+ // and the duplicated preview output is the whole problem.
843
+ const api = new IfcAPI();
844
+ await api.Init();
845
+ let previews = 0;
846
+ const modelID = await api.OpenModelStreamed(new Uint8Array(fs.readFileSync("data/index.ifc")), { ...SHARD_SETTINGS, ON_PREVIEW_MESH: () => {
847
+ ++previews;
848
+ } });
849
+ // The preview really did run, so the refusal below is about something
850
+ // that happened rather than a flag nobody acted on.
851
+ expect(previews).toBeGreaterThan(0);
852
+ expect(() => api.SetGeometryShard(modelID, { index: 0, count: 2 }))
853
+ .toThrow(/ON_PREVIEW_MESH/);
854
+ api.CloseModel(modelID);
855
+ }, 240000);
856
+ test("a shard cannot be claimed on a model opened without DEFER_GEOMETRY", async () => {
857
+ // Sharding only narrows the deferred pump's worklists. A classic
858
+ // open has already extracted everything, so the claim would be
859
+ // accepted and then do nothing: ExtractGeometryBatch returns zero
860
+ // work and StreamAllMeshes serves the whole scene. A coordinator
861
+ // that forgot the flag would get the COMPLETE model from every
862
+ // worker while believing it had a partition.
863
+ const api = new IfcAPI();
864
+ await api.Init();
865
+ const modelID = await api.OpenModelStreamed(new Uint8Array(fs.readFileSync("data/index.ifc")), { COORDINATE_TO_ORIGIN: false, USE_FAST_BOOLS: true });
866
+ expect(() => api.SetGeometryShard(modelID, { index: 0, count: 2 }))
867
+ .toThrow(/requires DEFER_GEOMETRY/);
868
+ // N=1 is still fine: it asks for the whole model, which is exactly
869
+ // what a classic open delivers.
870
+ expect(api.SetGeometryShard(modelID, { index: 0, count: 1 }))
871
+ .toBe(true);
872
+ api.CloseModel(modelID);
873
+ }, 240000);
874
+ test("a shard descriptor is snapshotted, not retained", async () => {
875
+ // A coordinator configuring several instances from one reused object is
876
+ // the natural way to write an in-process pool. If the descriptor were
877
+ // retained, every proxy would read its FINAL index at first pump —
878
+ // several workers claiming one shard, the rest of the model claimed by
879
+ // nobody — and each call would still have passed validation.
880
+ const api = new IfcAPI();
881
+ await api.Init();
882
+ const fixture = new Uint8Array(fs.readFileSync("data/mapped_shared_representation.ifc"));
883
+ const descriptor = { index: 0, count: 2 };
884
+ const modelID = await api.OpenModelStreamed(fixture, SHARD_SETTINGS);
885
+ expect(api.SetGeometryShard(modelID, descriptor)).toBe(true);
886
+ // The coordinator moves on to configuring the next worker.
887
+ descriptor.index = 1;
888
+ const delivered = [];
889
+ for (;;) {
890
+ const { extracted, remaining } = api.ExtractGeometryBatch(modelID, 4, (mesh) => {
891
+ for (let where = 0; where < mesh.geometries.size(); ++where) {
892
+ delivered.push(`${mesh.expressID}/` +
893
+ `${mesh.geometries.get(where).geometryExpressID}`);
894
+ }
895
+ });
896
+ if (remaining === 0 && extracted === 0) {
897
+ break;
898
+ }
899
+ }
900
+ // Shard 0's contents, not shard 1's. Compared against a model that
901
+ // claims shard 0 from a descriptor nobody touches.
902
+ const referenceApi = new IfcAPI();
903
+ await referenceApi.Init();
904
+ const referenceID = await referenceApi.OpenModelStreamed(fixture, SHARD_SETTINGS);
905
+ referenceApi.SetGeometryShard(referenceID, { index: 0, count: 2 });
906
+ const reference = [];
907
+ for (;;) {
908
+ const { extracted, remaining } = referenceApi.ExtractGeometryBatch(referenceID, 4, (mesh) => {
909
+ for (let where = 0; where < mesh.geometries.size(); ++where) {
910
+ reference.push(`${mesh.expressID}/` +
911
+ `${mesh.geometries.get(where).geometryExpressID}`);
912
+ }
913
+ });
914
+ if (remaining === 0 && extracted === 0) {
915
+ break;
916
+ }
917
+ }
918
+ expect(reference.length).toBeGreaterThan(0);
919
+ expect(delivered.sort()).toEqual(reference.sort());
920
+ api.CloseModel(modelID);
921
+ referenceApi.CloseModel(referenceID);
922
+ }, 240000);
923
+ test("an unsharded model is unaffected by the shard preconditions", async () => {
924
+ // The guards must be about workers agreeing with each other and nothing
925
+ // else. A model that never claims a shard recentres and pumps exactly as
926
+ // before — without this, the checks would be a behaviour change for
927
+ // every existing caller, Share included.
928
+ const api = new IfcAPI();
929
+ await api.Init();
930
+ const modelID = await api.OpenModelStreamed(new Uint8Array(fs.readFileSync("data/index.ifc")), { COORDINATE_TO_ORIGIN: true, USE_FAST_BOOLS: true, DEFER_GEOMETRY: true });
931
+ let delivered = 0;
932
+ for (;;) {
933
+ const { extracted, remaining } = api.ExtractGeometryBatch(modelID, 4, (mesh) => {
934
+ delivered += mesh.geometries.size();
935
+ });
936
+ if (remaining === 0 && extracted === 0) {
937
+ break;
938
+ }
939
+ }
940
+ expect(delivered).toBeGreaterThan(0);
941
+ api.CloseModel(modelID);
942
+ }, 240000);
583
943
  test("ExtractGeometryBatch is a safe no-op on non-deferred models", async () => {
584
944
  const modelID = await api.OpenModelStreamed(buffer, SETTINGS);
585
945
  expect(api.ExtractGeometryBatch(modelID, 8))
@@ -16,6 +16,15 @@ export interface IfcApiModelPassthrough {
16
16
  releaseGeometry?(): boolean;
17
17
  /** Metres per model unit (see IfcAPI.GetLinearScalingFactor). */
18
18
  linearScalingFactor?: number;
19
+ /**
20
+ * Claim one shard of this model's geometry (conway extension, M3) — see
21
+ * IfcAPI.SetGeometryShard. Optional: passthroughs without demand worklists
22
+ * (AP214/STEP) have nothing to shard.
23
+ */
24
+ setGeometryShard?(shard?: {
25
+ index: number;
26
+ count: number;
27
+ }): void;
19
28
  /**
20
29
  * Set the resident-geometry budget in bytes (conway extension, M3) —
21
30
  * see IfcAPI.SetGeometryBudget. Optional so non-IFC passthroughs, whose
@@ -1 +1 @@
1
- {"version":3,"file":"ifc_api_model_passthrough.d.ts","sourceRoot":"","sources":["../../../../src/compat/web-ifc/ifc_api_model_passthrough.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAA;AACvE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,WAAW,CAAA;AACtE,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAA;AAGhE,MAAM,WAAW,sBAAsB;IAErC,UAAU,EAAE,qBAAqB,CAAA;IAEjC,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,QAAQ,CAAA;IACxC,eAAe,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAA;IACnC,wBAAwB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,YAAY,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,IAAI,GAAG,IAAI,CAAA;IACvF,eAAe,CAAC,YAAY,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,IAAI,GAAG,IAAI,CAAA;IAC7D;;;OAGG;IACH;gEAC4D;IAC5D,eAAe,CAAC,IAAI,OAAO,CAAA;IAE3B,iEAAiE;IACjE,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAE5B;;;;OAIG;IACH,iBAAiB,CAAC,CAAE,KAAK,EAAE,MAAM,GAAI;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAA;IAE/E,oBAAoB,CAAC,CACnB,SAAS,EAAE,MAAM,EACjB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,IAAI,GAAG;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAC,CAAA;IAElF;;;OAGG;IACH,yBAAyB,CAAC,CACxB,SAAS,EAAE,MAAM,EACjB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,IAAI,GACvC,OAAO,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAC,CAAC,CAAA;IACjD,qBAAqB,IAAI,MAAM,EAAE,CAAA;IAEjC;;;;;;;OAOG;IACH,sBAAsB,CAAC,IAAI,MAAM,EAAE,CAAA;IACnC,WAAW,IAAI,MAAM,CAAC,MAAM,CAAC,CAAA;IAC7B,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAA;IAChD,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,CAAA;IAC9C,WAAW,CAAC,IAAI,EAAE,GAAG,GAAG,IAAI,CAAA;IAC5B,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAAA;IAC5D,WAAW,CAAC,iBAAiB,EAAE,MAAM,GAAG,WAAW,CAAA;IAEnD;;;OAGG;IACH,kBAAkB,CAAC,IAAI,IAAI,CAAA;IAE3B;;;OAGG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAEnC,wEAAwE;IACxE,QAAQ,CAAC,cAAc,CAAC,EAAE;QACxB,UAAU,EAAE,MAAM,CAAA;QAClB,SAAS,EAAE,MAAM,CAAA;QACjB,SAAS,EAAE,MAAM,CAAA;QACjB,OAAO,EAAE,MAAM,CAAA;QACf,QAAQ,EAAE,MAAM,CAAA;QAChB,MAAM,EAAE,MAAM,CAAA;KACf,CAAA;IAED;;;OAGG;IACH,0BAA0B,CAAC,CACzB,KAAK,EAAE,qBAAqB,EAC5B,UAAU,CAAC,EAAE,MAAM,EACnB,iBAAiB,CAAC,EAAE,MAAM,GAAI,IAAI,CAAA;IAEpC;;;OAGG;IACH,kBAAkB,CAAC,CAAE,SAAS,EAAE,MAAM,GAAI,OAAO,CAAE,IAAI,CAAE,CAAA;IAEzD;;;;;OAKG;IACH,cAAc,CAAC,IAAI,gBAAgB,CAAE,MAAM,CAAE,CAAA;CAC9C"}
1
+ {"version":3,"file":"ifc_api_model_passthrough.d.ts","sourceRoot":"","sources":["../../../../src/compat/web-ifc/ifc_api_model_passthrough.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAA;AACvE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,WAAW,CAAA;AACtE,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAA;AAGhE,MAAM,WAAW,sBAAsB;IAErC,UAAU,EAAE,qBAAqB,CAAA;IAEjC,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,QAAQ,CAAA;IACxC,eAAe,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAA;IACnC,wBAAwB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,YAAY,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,IAAI,GAAG,IAAI,CAAA;IACvF,eAAe,CAAC,YAAY,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,IAAI,GAAG,IAAI,CAAA;IAC7D;;;OAGG;IACH;gEAC4D;IAC5D,eAAe,CAAC,IAAI,OAAO,CAAA;IAE3B,iEAAiE;IACjE,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAE5B;;;;OAIG;IACH,gBAAgB,CAAC,CAAE,KAAK,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,GAAI,IAAI,CAAA;IAEnE;;;;OAIG;IACH,iBAAiB,CAAC,CAAE,KAAK,EAAE,MAAM,GAAI;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAA;IAE/E,oBAAoB,CAAC,CACnB,SAAS,EAAE,MAAM,EACjB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,IAAI,GAAG;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAC,CAAA;IAElF;;;OAGG;IACH,yBAAyB,CAAC,CACxB,SAAS,EAAE,MAAM,EACjB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,IAAI,GACvC,OAAO,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAC,CAAC,CAAA;IACjD,qBAAqB,IAAI,MAAM,EAAE,CAAA;IAEjC;;;;;;;OAOG;IACH,sBAAsB,CAAC,IAAI,MAAM,EAAE,CAAA;IACnC,WAAW,IAAI,MAAM,CAAC,MAAM,CAAC,CAAA;IAC7B,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAA;IAChD,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,CAAA;IAC9C,WAAW,CAAC,IAAI,EAAE,GAAG,GAAG,IAAI,CAAA;IAC5B,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAAA;IAC5D,WAAW,CAAC,iBAAiB,EAAE,MAAM,GAAG,WAAW,CAAA;IAEnD;;;OAGG;IACH,kBAAkB,CAAC,IAAI,IAAI,CAAA;IAE3B;;;OAGG;IACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAEnC,wEAAwE;IACxE,QAAQ,CAAC,cAAc,CAAC,EAAE;QACxB,UAAU,EAAE,MAAM,CAAA;QAClB,SAAS,EAAE,MAAM,CAAA;QACjB,SAAS,EAAE,MAAM,CAAA;QACjB,OAAO,EAAE,MAAM,CAAA;QACf,QAAQ,EAAE,MAAM,CAAA;QAChB,MAAM,EAAE,MAAM,CAAA;KACf,CAAA;IAED;;;OAGG;IACH,0BAA0B,CAAC,CACzB,KAAK,EAAE,qBAAqB,EAC5B,UAAU,CAAC,EAAE,MAAM,EACnB,iBAAiB,CAAC,EAAE,MAAM,GAAI,IAAI,CAAA;IAEpC;;;OAGG;IACH,kBAAkB,CAAC,CAAE,SAAS,EAAE,MAAM,GAAI,OAAO,CAAE,IAAI,CAAE,CAAA;IAEzD;;;;;OAKG;IACH,cAAc,CAAC,IAAI,gBAAgB,CAAE,MAAM,CAAE,CAAA;CAC9C"}