@bldrs-ai/conway 1.538.1511 → 1.543.1513
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/compiled/examples/browser-bundled.cjs +39 -5
- package/compiled/examples/cli-bundled.cjs +89 -7
- package/compiled/examples/cli-step-bundled.cjs +39 -5
- package/compiled/examples/validator-bundled.cjs +39 -5
- package/compiled/src/compat/web-ifc/ifc_api_preview_channel.test.js +264 -1
- package/compiled/src/compat/web-ifc/store_preview_channel.d.ts +79 -0
- package/compiled/src/compat/web-ifc/store_preview_channel.d.ts.map +1 -1
- package/compiled/src/compat/web-ifc/store_preview_channel.js +237 -14
- package/compiled/src/compat/web-ifc/store_preview_channel.test.js +270 -1
- package/compiled/src/compat/web-ifc/streamed_preview_channel.d.ts +106 -1
- package/compiled/src/compat/web-ifc/streamed_preview_channel.d.ts.map +1 -1
- package/compiled/src/compat/web-ifc/streamed_preview_channel.js +269 -17
- package/compiled/src/core/progress_log.d.ts +75 -2
- package/compiled/src/core/progress_log.d.ts.map +1 -1
- package/compiled/src/core/progress_log.js +59 -2
- package/compiled/src/core/progress_log.test.js +75 -1
- package/compiled/src/ifc/dangling_placement_error.d.ts +35 -0
- package/compiled/src/ifc/dangling_placement_error.d.ts.map +1 -0
- package/compiled/src/ifc/dangling_placement_error.js +38 -0
- package/compiled/src/ifc/ifc_geometry_extraction.d.ts +6 -0
- package/compiled/src/ifc/ifc_geometry_extraction.d.ts.map +1 -1
- package/compiled/src/ifc/ifc_geometry_extraction.js +29 -0
- package/compiled/src/step/dangling_reference_error.d.ts +34 -0
- package/compiled/src/step/dangling_reference_error.d.ts.map +1 -0
- package/compiled/src/step/dangling_reference_error.js +36 -0
- package/compiled/src/step/step_entity_base.d.ts +17 -0
- package/compiled/src/step/step_entity_base.d.ts.map +1 -1
- package/compiled/src/step/step_entity_base.js +28 -4
- package/compiled/src/version/version.js +1 -1
- package/compiled/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -6,9 +6,10 @@
|
|
|
6
6
|
// same geometry ids, same placed transforms — since the durable pump the
|
|
7
7
|
// preview hands over to is already pinned to classic parity.
|
|
8
8
|
import * as fs from "fs";
|
|
9
|
-
import { beforeAll, describe, expect, test } from "@jest/globals";
|
|
9
|
+
import { beforeAll, describe, expect, jest, test } from "@jest/globals";
|
|
10
10
|
import { ConwayGeometry } from "../../../dependencies/conway-geom/index.js";
|
|
11
11
|
import IfcStepParser from "../../ifc/ifc_step_parser.js";
|
|
12
|
+
import Logger from "../../logging/logger.js";
|
|
12
13
|
import { BufferByteSource } from "../../step/parsing/byte_source.js";
|
|
13
14
|
import { ColumnarIndexSink, } from "../../step/parsing/columnar_index.js";
|
|
14
15
|
import { ParseResult } from "../../step/parsing/step_parser.js";
|
|
@@ -380,4 +381,266 @@ describe("StreamedPreviewChannel", () => {
|
|
|
380
381
|
}
|
|
381
382
|
}
|
|
382
383
|
}, 240000);
|
|
384
|
+
test("a tail-placement file recovers its deferred products", () => {
|
|
385
|
+
// The resident twin of the store channel's test for conway#542.
|
|
386
|
+
// data/index_tail_placements.ifc is index_georeferenced_multicell.ifc
|
|
387
|
+
// with every leaf point/direction record moved to the end of DATA —
|
|
388
|
+
// same ids, same text, hostile order. It is the Archicad shape at
|
|
389
|
+
// fixture scale: its products reference a placement chain that bottoms
|
|
390
|
+
// out after them, so an index stopping short of the tail cannot place
|
|
391
|
+
// any of them. The multicell fixture rather than index.ifc because it
|
|
392
|
+
// carries enough products that one attempt cannot exhaust the
|
|
393
|
+
// generation — which is what leaves the preemption path, not the
|
|
394
|
+
// exhaustion path, as the only way to rebuild.
|
|
395
|
+
const tailText = fs.readFileSync("data/index_tail_placements.ifc", "utf8");
|
|
396
|
+
const lines = tailText.split("\n");
|
|
397
|
+
const firstLeaf = lines.findIndex((line) => /=\s*IFC(CARTESIANPOINT|DIRECTION)/.test(line));
|
|
398
|
+
expect(firstLeaf).toBeGreaterThan(0);
|
|
399
|
+
// A genuine prefix, closed off so it parses: every record up to the
|
|
400
|
+
// leaf block, and nothing after it. The full file is stage two.
|
|
401
|
+
const prefixText = `${lines.slice(0, firstLeaf).join("\n")}\nENDSEC;\nEND-ISO-10303-21;\n`;
|
|
402
|
+
const prefixBytes = new Uint8Array(Buffer.from(prefixText, "latin1"));
|
|
403
|
+
const tailBytes = new Uint8Array(Buffer.from(tailText, "latin1"));
|
|
404
|
+
const sink = new ColumnarIndexSink();
|
|
405
|
+
const payloads = [];
|
|
406
|
+
// The source buffer is the WHOLE file throughout, as it is on a
|
|
407
|
+
// resident open — only the index grows.
|
|
408
|
+
const channel = new StreamedPreviewChannel(tailBytes, conwayGeometry, sink, ifcPreviewAdapter(), true, (mesh) => payloads.push(mesh), void 0, void 0, 1);
|
|
409
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
410
|
+
const internals = channel;
|
|
411
|
+
// One unit per tick, so stage one leaves units UNATTEMPTED. That is
|
|
412
|
+
// what forces the preemption path: with units still pending, a channel
|
|
413
|
+
// that only rebuilds on exhaustion keeps its starved generation and
|
|
414
|
+
// never looks at the deferrals again.
|
|
415
|
+
internals.tickBudgetMs_ = Number.MAX_SAFE_INTEGER;
|
|
416
|
+
internals.tickMaxAttempts_ = 1;
|
|
417
|
+
// Stage one: index only the prefix, then let the channel work it.
|
|
418
|
+
expect(buildIndexStreaming(new BufferByteSource(prefixBytes), IfcStepParser.Instance, POOL, void 0, sink).result).toBe(ParseResult.COMPLETE);
|
|
419
|
+
internals.lastInlineTick_ = 0;
|
|
420
|
+
channel.maybeTickInline();
|
|
421
|
+
const afterPrefix = channel.previewYield;
|
|
422
|
+
// The fixture has to actually exercise the path, or the rest proves
|
|
423
|
+
// nothing about it — and units must be left over, or the rebuild would
|
|
424
|
+
// happen by exhaustion and prove nothing about preemption.
|
|
425
|
+
expect(afterPrefix.deferredOnPlacement).toBeGreaterThan(0);
|
|
426
|
+
expect(afterPrefix.emitted).toBe(0);
|
|
427
|
+
expect(afterPrefix.firstMeshMs).toBeUndefined();
|
|
428
|
+
expect(internals.unitOrdinal_)
|
|
429
|
+
.toBeLessThan(internals.generation_.generation.unitCount);
|
|
430
|
+
// Stage two: the same reset-and-replay the streaming builder performs
|
|
431
|
+
// when it grows its window, so top-level localIDs stay in dense parse
|
|
432
|
+
// order and the deferred ORDINALS the channel is holding still mean
|
|
433
|
+
// what they meant (see ColumnarIndexSink.reset).
|
|
434
|
+
sink.reset();
|
|
435
|
+
expect(buildIndexStreaming(new BufferByteSource(tailBytes), IfcStepParser.Instance, POOL, void 0, sink).result).toBe(ParseResult.COMPLETE);
|
|
436
|
+
// Exactly one attempt in this tick. That is what makes this an
|
|
437
|
+
// assertion about PREEMPTION: with units still pending, a channel that
|
|
438
|
+
// rebuilds only on exhaustion spends the attempt on the next fresh unit
|
|
439
|
+
// against the old starved generation, and the retry never happens.
|
|
440
|
+
internals.lastInlineTick_ = 0;
|
|
441
|
+
channel.maybeTickInline();
|
|
442
|
+
const afterFull = channel.previewYield;
|
|
443
|
+
// Both halves of the fix, and `retried` is what separates them from a
|
|
444
|
+
// channel that merely got lucky on a later unit. Without the retry
|
|
445
|
+
// queue a deferred unit is attempted once, at the most index-starved
|
|
446
|
+
// generation it appears in, and abandoned. Without preemptive rebuilds
|
|
447
|
+
// the generation is kept while units remain, so the deferrals are never
|
|
448
|
+
// revisited against the longer index. Either one missing holds this at
|
|
449
|
+
// zero.
|
|
450
|
+
expect(afterFull.retried).toBeGreaterThan(0);
|
|
451
|
+
expect(afterFull.emitted).toBeGreaterThan(0);
|
|
452
|
+
// And the recovered products become pixels: one attempt per tick is
|
|
453
|
+
// what makes the assertions above about preemption, but a single unit
|
|
454
|
+
// need not be one that carries geometry (a site or a storey extracts
|
|
455
|
+
// and walks no buffer geometry), so let the channel run out the
|
|
456
|
+
// recovered queue before reading time-to-first-pixel.
|
|
457
|
+
internals.tickMaxAttempts_ = Number.MAX_SAFE_INTEGER;
|
|
458
|
+
internals.lastInlineTick_ = 0;
|
|
459
|
+
channel.maybeTickInline();
|
|
460
|
+
expect(payloads.length).toBeGreaterThan(0);
|
|
461
|
+
expect(channel.previewYield.firstMeshMs).toBeGreaterThanOrEqual(0);
|
|
462
|
+
channel.stop();
|
|
463
|
+
}, 240000);
|
|
464
|
+
test("a generation is preempted only when it is deferring", () => {
|
|
465
|
+
// The counterweight. Rebuilding on index growth alone regressed the
|
|
466
|
+
// case that already worked: PSB, which defers nothing, went from a
|
|
467
|
+
// first mesh at 269ms to 495ms on the store path because it kept paying
|
|
468
|
+
// for rebuilds it had no use for. index.ifc is that shape at fixture
|
|
469
|
+
// scale, so the same two-stage growth must leave its generation alone.
|
|
470
|
+
const sink = new ColumnarIndexSink();
|
|
471
|
+
const channel = new StreamedPreviewChannel(data, conwayGeometry, sink, ifcPreviewAdapter(), true, () => { }, void 0, void 0, 1);
|
|
472
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
473
|
+
const internals = channel;
|
|
474
|
+
// One unit per tick, so the generation is nowhere near exhausted when
|
|
475
|
+
// the index grows — otherwise the exhaustion path would rebuild and
|
|
476
|
+
// this would assert nothing about preemption.
|
|
477
|
+
internals.tickBudgetMs_ = Number.MAX_SAFE_INTEGER;
|
|
478
|
+
internals.tickMaxAttempts_ = 1;
|
|
479
|
+
expect(buildIndexStreaming(new BufferByteSource(data), IfcStepParser.Instance, POOL, void 0, sink).result).toBe(ParseResult.COMPLETE);
|
|
480
|
+
internals.lastInlineTick_ = 0;
|
|
481
|
+
channel.maybeTickInline();
|
|
482
|
+
const snapshotRecords = internals.lastSnapshotRecords_;
|
|
483
|
+
expect(snapshotRecords).toBeGreaterThan(0);
|
|
484
|
+
expect(channel.previewYield.deferredOnPlacement).toBe(0);
|
|
485
|
+
// Index growth well past GENERATION_GROWTH_FACTOR, with units still
|
|
486
|
+
// pending and nothing deferring: the generation must be kept.
|
|
487
|
+
sink.reset();
|
|
488
|
+
for (let repeat = 0; repeat < 3; ++repeat) {
|
|
489
|
+
expect(buildIndexStreaming(new BufferByteSource(data), IfcStepParser.Instance, POOL, void 0, sink).result).toBe(ParseResult.COMPLETE);
|
|
490
|
+
}
|
|
491
|
+
expect(sink.topLevelCount).toBeGreaterThan(snapshotRecords * 2);
|
|
492
|
+
internals.lastInlineTick_ = 0;
|
|
493
|
+
channel.maybeTickInline();
|
|
494
|
+
expect(internals.lastSnapshotRecords_).toBe(snapshotRecords);
|
|
495
|
+
expect(channel.previewYield.retried).toBe(0);
|
|
496
|
+
channel.stop();
|
|
497
|
+
}, 240000);
|
|
498
|
+
test("retry mode preempts a generation whose units captured nothing", () => {
|
|
499
|
+
// AP214's half of conway#542. `retryEmptyUnits` already re-runs empty
|
|
500
|
+
// units, so that schema never abandoned a deferral — but it kept a
|
|
501
|
+
// stale generation for the same reason the IFC path did: the growth
|
|
502
|
+
// gate sat behind "this generation still has units", and a scan that
|
|
503
|
+
// never finishes never reaches it. An empty unit is this schema's
|
|
504
|
+
// deferral signal (the adapter cannot classify a failure — an assembly
|
|
505
|
+
// unit simply produces no instances until the solids it references are
|
|
506
|
+
// indexed), so index growth must preempt mid-scan.
|
|
507
|
+
const UNIT_COUNT = 3;
|
|
508
|
+
const runsPerGeneration = [];
|
|
509
|
+
let reportedRecords = 2048;
|
|
510
|
+
const fakeSink = {
|
|
511
|
+
get topLevelCount() {
|
|
512
|
+
return reportedRecords;
|
|
513
|
+
},
|
|
514
|
+
snapshot: () => ({}),
|
|
515
|
+
};
|
|
516
|
+
const makeGeneration = () => {
|
|
517
|
+
const runs = [];
|
|
518
|
+
runsPerGeneration.push(runs);
|
|
519
|
+
return {
|
|
520
|
+
// Empty scene: units "execute" but never capture, so no unit ever
|
|
521
|
+
// completes and every generation re-runs all of them.
|
|
522
|
+
scene: { *walk() { } },
|
|
523
|
+
unitCount: UNIT_COUNT,
|
|
524
|
+
linearScalingFactor: 1,
|
|
525
|
+
runUnits: (from) => {
|
|
526
|
+
runs.push(from);
|
|
527
|
+
return 1;
|
|
528
|
+
},
|
|
529
|
+
geometryExpressID: () => void 0,
|
|
530
|
+
recenter: false,
|
|
531
|
+
dispose: () => { },
|
|
532
|
+
};
|
|
533
|
+
};
|
|
534
|
+
const adapter = {
|
|
535
|
+
retryEmptyUnits: true,
|
|
536
|
+
buildGeneration: () => makeGeneration(),
|
|
537
|
+
};
|
|
538
|
+
const channel = new StreamedPreviewChannel(data, conwayGeometry, fakeSink, adapter, false, () => { }, void 0, void 0, 1);
|
|
539
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
540
|
+
const internals = channel;
|
|
541
|
+
// One unit per tick, so the scan is deliberately left unfinished.
|
|
542
|
+
internals.tickBudgetMs_ = Number.MAX_SAFE_INTEGER;
|
|
543
|
+
internals.tickMaxAttempts_ = 1;
|
|
544
|
+
/* eslint-enable @typescript-eslint/no-explicit-any */
|
|
545
|
+
const forceTick = () => {
|
|
546
|
+
internals.lastInlineTick_ = 0;
|
|
547
|
+
internals.tickIntervalMs_ = 0;
|
|
548
|
+
channel.maybeTickInline();
|
|
549
|
+
};
|
|
550
|
+
// Generation 1 runs one unit, which captures nothing.
|
|
551
|
+
forceTick();
|
|
552
|
+
expect(runsPerGeneration.length).toBe(1);
|
|
553
|
+
expect(runsPerGeneration[0]).toEqual([0]);
|
|
554
|
+
// The index grows past the gate with the scan still mid-list. Without
|
|
555
|
+
// preemption the channel keeps generation 1 and runs its unit 1; with
|
|
556
|
+
// it, a fresh generation restarts the scan against the longer index.
|
|
557
|
+
reportedRecords *= 4;
|
|
558
|
+
forceTick();
|
|
559
|
+
expect(runsPerGeneration.length).toBe(2);
|
|
560
|
+
expect(runsPerGeneration[1]).toEqual([0]);
|
|
561
|
+
channel.stop();
|
|
562
|
+
}, 240000);
|
|
563
|
+
test("preemption preserves the unconsumed suffix of the retry queue", () => {
|
|
564
|
+
// Codex round 1 on #543: preemption replaced retryQueue_ outright with
|
|
565
|
+
// this generation's fresh deferredForRetry_, discarding whatever the
|
|
566
|
+
// OLD queue's tail had not yet been popped. A retry queue can easily
|
|
567
|
+
// span more than one tick's attempt budget (bounded per tick, unbounded
|
|
568
|
+
// in total), so index growth can preempt a generation mid-drain of it
|
|
569
|
+
// — and every un-popped entry is a unit whose unitOrdinal_ has already
|
|
570
|
+
// passed, so replacing rather than concatenating strands it exactly
|
|
571
|
+
// the way abandoned deferrals were stranded before this queue existed
|
|
572
|
+
// (conway#542).
|
|
573
|
+
//
|
|
574
|
+
// The bug is purely mechanical (which array wins the assignment), so
|
|
575
|
+
// this seeds the private queue state directly and forces the growth
|
|
576
|
+
// gate via lastSnapshotRecords_ rather than engineering a real
|
|
577
|
+
// multi-tick deferral sequence.
|
|
578
|
+
const fakeGeneration = () => ({
|
|
579
|
+
scene: { *walk() { } },
|
|
580
|
+
unitCount: 1,
|
|
581
|
+
linearScalingFactor: 1,
|
|
582
|
+
runUnits: () => 0,
|
|
583
|
+
geometryExpressID: () => void 0,
|
|
584
|
+
recenter: false,
|
|
585
|
+
dispose: () => { },
|
|
586
|
+
});
|
|
587
|
+
const fakeSink = {
|
|
588
|
+
get topLevelCount() {
|
|
589
|
+
return 2048;
|
|
590
|
+
},
|
|
591
|
+
snapshot: () => ({}),
|
|
592
|
+
};
|
|
593
|
+
const adapter = { buildGeneration: () => fakeGeneration() };
|
|
594
|
+
const channel = new StreamedPreviewChannel(data, conwayGeometry, fakeSink, adapter, false, () => { }, void 0, void 0, 1);
|
|
595
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
596
|
+
const internals = channel;
|
|
597
|
+
// Generation 1: a real, successful build (active must be defined for
|
|
598
|
+
// the preemption branch to even be reachable).
|
|
599
|
+
expect(internals.ensureGeneration_()).toBe(true);
|
|
600
|
+
// A retry queue spanning more than one tick's budget: 6 queued
|
|
601
|
+
// retries, only the first 3 consumed (retryCursor_ short of
|
|
602
|
+
// retryQueue_.length is exactly "mid-drain") before the index grew
|
|
603
|
+
// again. deferredForRetry_ is this generation's OWN fresh deferral —
|
|
604
|
+
// the only thing the buggy version kept.
|
|
605
|
+
internals.retryQueue_ = [10, 11, 12, 13, 14, 15];
|
|
606
|
+
internals.retryCursor_ = 3;
|
|
607
|
+
internals.deferredForRetry_ = [99];
|
|
608
|
+
// Force the growth gate trivially open on the next check, without
|
|
609
|
+
// needing the sink to actually grow: the gate is a ratio against
|
|
610
|
+
// lastSnapshotRecords_, not an absolute count.
|
|
611
|
+
internals.lastSnapshotRecords_ = 1;
|
|
612
|
+
// Preemption fires: active is defined, growthReady (2048 >= 1 * factor),
|
|
613
|
+
// and hasDeferred_() is true (deferredForRetry_.length > 0).
|
|
614
|
+
expect(internals.ensureGeneration_()).toBe(true);
|
|
615
|
+
// The unconsumed suffix of the old queue (indices 3..5) must survive,
|
|
616
|
+
// carried ahead of this generation's own fresh deferral — not replaced
|
|
617
|
+
// by it.
|
|
618
|
+
expect(internals.retryQueue_).toEqual([13, 14, 15, 99]);
|
|
619
|
+
expect(internals.retryCursor_).toBe(0);
|
|
620
|
+
channel.stop();
|
|
621
|
+
}, 240000);
|
|
622
|
+
test("reports a preview line even when nothing was ever attempted", () => {
|
|
623
|
+
// Codex round 1 on #543: stop() suppressed the Preview line unless
|
|
624
|
+
// emittedUnits_ or deferredUnits_ was nonzero. A channel that never
|
|
625
|
+
// reached firstGenerationMinRecords -- or whose every generation build
|
|
626
|
+
// threw -- leaves both at zero, and that is exactly the worst-case
|
|
627
|
+
// blank-first-load conway#542 exists to make diagnosable: an enabled
|
|
628
|
+
// preview that produced nothing must not read the same as a preview
|
|
629
|
+
// that never ran. formatPreviewLine already renders the zero case as
|
|
630
|
+
// "no mesh, 0 meshes from 0 units, 0 deferred".
|
|
631
|
+
const fakeSink = {
|
|
632
|
+
get topLevelCount() {
|
|
633
|
+
return 0;
|
|
634
|
+
},
|
|
635
|
+
snapshot: () => ({}),
|
|
636
|
+
};
|
|
637
|
+
const infoSpy = jest.spyOn(Logger, "info").mockImplementation(() => { });
|
|
638
|
+
// Default firstGenerationMinRecords (1024): with topLevelCount pinned
|
|
639
|
+
// at 0, ensureGeneration_ never builds a generation, so the channel
|
|
640
|
+
// reaches stop() having attempted nothing at all.
|
|
641
|
+
const channel = new StreamedPreviewChannel(data, conwayGeometry, fakeSink, { buildGeneration: () => { throw new Error("must not be called"); } }, false, () => { });
|
|
642
|
+
channel.stop();
|
|
643
|
+
expect(infoSpy).toHaveBeenCalledWith(expect.stringContaining("Preview: no mesh, 0 meshes from 0 units, 0 deferred"));
|
|
644
|
+
infoSpy.mockRestore();
|
|
645
|
+
});
|
|
383
646
|
});
|
|
@@ -28,6 +28,40 @@ export declare class StorePreviewChannel {
|
|
|
28
28
|
coordinationMatrix?: number[];
|
|
29
29
|
private stopped_;
|
|
30
30
|
private emittedUnits_;
|
|
31
|
+
/**
|
|
32
|
+
* Preview meshes handed to `onMesh_`. Tracked apart from
|
|
33
|
+
* {@link emittedUnits_} because the two genuinely diverge: a product can
|
|
34
|
+
* place several meshes, and a product with no Representation extracts
|
|
35
|
+
* cleanly while placing none — `extractProductGeometry` returns early on
|
|
36
|
+
* a null Representation and `extractProductGeometryByLocalID` still
|
|
37
|
+
* answers true. Reporting only units let the load log say "no mesh, 20
|
|
38
|
+
* emitted" about one load (codex round 2 on #543).
|
|
39
|
+
*/
|
|
40
|
+
private meshesEmitted_;
|
|
41
|
+
private deferredUnits_;
|
|
42
|
+
private deferredOnPlacement_;
|
|
43
|
+
/**
|
|
44
|
+
* Products that deferred under the CURRENT generation, promoted to
|
|
45
|
+
* {@link retryQueue_} when the next one is built. Held separately so a
|
|
46
|
+
* retry always runs against a longer index than the attempt that failed —
|
|
47
|
+
* re-running one inside its own generation would fail identically and
|
|
48
|
+
* spin.
|
|
49
|
+
*/
|
|
50
|
+
private deferredForRetry_;
|
|
51
|
+
private retryQueue_;
|
|
52
|
+
private retryCursor_;
|
|
53
|
+
private retriedUnits_;
|
|
54
|
+
/**
|
|
55
|
+
* Ms from channel construction to the first PLACED PRODUCT payload —
|
|
56
|
+
* time-to-first-pixel, the number conway#542 exists to move. The spatial
|
|
57
|
+
* plates are deliberately not counted: they are the building's wireframe
|
|
58
|
+
* skeleton, they go out on a different schedule (see
|
|
59
|
+
* {@link maybeEmitEarlySpatialPlates_}), and counting them would report
|
|
60
|
+
* first pixels for a load whose products are all still deferring.
|
|
61
|
+
* {@link earlyPlateCount} is where those are visible.
|
|
62
|
+
*/
|
|
63
|
+
private firstMeshMs_?;
|
|
64
|
+
private readonly startedMs_;
|
|
31
65
|
private emittedBytes_;
|
|
32
66
|
private unitOrdinal_;
|
|
33
67
|
private lastInlineTick_;
|
|
@@ -61,6 +95,35 @@ export declare class StorePreviewChannel {
|
|
|
61
95
|
constructor(store_: StepExternalByteStore, sink_: ColumnarIndexSink<number>, conwaywasm_: ConwayGeometry, coordinateToOrigin_: boolean, onMesh_: (mesh: PreviewMeshPayload) => void, maxUnits?: number, maxBytes?: number, firstGenerationMinRecords?: number);
|
|
62
96
|
get capped(): boolean;
|
|
63
97
|
get emittedUnits(): number;
|
|
98
|
+
/**
|
|
99
|
+
* What the preview delivered, and how fast.
|
|
100
|
+
*
|
|
101
|
+
* `firstMeshMs` is time-to-first-pixel measured from channel
|
|
102
|
+
* construction, undefined when no placed product was ever emitted.
|
|
103
|
+
* `meshes` counts what actually reached the consumer, `emitted` counts
|
|
104
|
+
* the products extraction accepted — they are not the same number in
|
|
105
|
+
* either direction, so the line reports both.
|
|
106
|
+
* `deferred` counts products a tick attempted and could not extract;
|
|
107
|
+
* `deferredOnPlacement` is the subset still waiting on a placement chain
|
|
108
|
+
* the prefix does not hold; `retried` counts attempts that were second
|
|
109
|
+
* looks at an earlier deferral rather than first attempts, so a channel
|
|
110
|
+
* whose retry path has silently stopped firing is visible rather than
|
|
111
|
+
* merely slower. A first load that shows nothing is a very
|
|
112
|
+
* different problem depending on that ratio — near 1.0 is the file-layout
|
|
113
|
+
* case a sharded parse attacks, anything else is not — and inferring it
|
|
114
|
+
* from a code comment is what conway#542 exists to stop.
|
|
115
|
+
*
|
|
116
|
+
* @return {object} `{firstMeshMs, meshes, emitted, deferred,
|
|
117
|
+
* deferredOnPlacement, retried}`
|
|
118
|
+
*/
|
|
119
|
+
get previewYield(): {
|
|
120
|
+
firstMeshMs?: number;
|
|
121
|
+
meshes: number;
|
|
122
|
+
emitted: number;
|
|
123
|
+
deferred: number;
|
|
124
|
+
deferredOnPlacement: number;
|
|
125
|
+
retried: number;
|
|
126
|
+
};
|
|
64
127
|
/** Products the current generation would run (test seam). */
|
|
65
128
|
get productCount(): number;
|
|
66
129
|
/**
|
|
@@ -120,6 +183,20 @@ export declare class StorePreviewChannel {
|
|
|
120
183
|
* @return {Promise<boolean>} True when a product was attempted.
|
|
121
184
|
*/
|
|
122
185
|
private tickOnce_;
|
|
186
|
+
/**
|
|
187
|
+
* Whether either queue still has a product to attempt.
|
|
188
|
+
*
|
|
189
|
+
* Static and fully parameterised so the two callers — the tick and the
|
|
190
|
+
* generation gate — cannot drift apart on what "pending" means, which is
|
|
191
|
+
* the bug that would silently strand the retry queue.
|
|
192
|
+
*
|
|
193
|
+
* @param retryCursor How far into the retry queue this generation is.
|
|
194
|
+
* @param retryLength The retry queue's length.
|
|
195
|
+
* @param ordinal The forward cursor into the generation's products.
|
|
196
|
+
* @param productCount That generation's product count.
|
|
197
|
+
* @return {boolean} True when something is left to attempt.
|
|
198
|
+
*/
|
|
199
|
+
private static hasPending_;
|
|
123
200
|
/**
|
|
124
201
|
* @return {Promise<boolean>} True when a generation with pending units exists.
|
|
125
202
|
*/
|
|
@@ -181,6 +258,8 @@ export declare class StorePreviewChannel {
|
|
|
181
258
|
/**
|
|
182
259
|
* Copy newly extracted instances out of wasm — same placement math
|
|
183
260
|
* as {@link StreamedPreviewChannel}.
|
|
261
|
+
*
|
|
262
|
+
* @return {number} Meshes emitted by this pass.
|
|
184
263
|
*/
|
|
185
264
|
private captureNewInstances_;
|
|
186
265
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store_preview_channel.d.ts","sourceRoot":"","sources":["../../../../src/compat/web-ifc/store_preview_channel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAY5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAA;AAGrE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAA;
|
|
1
|
+
{"version":3,"file":"store_preview_channel.d.ts","sourceRoot":"","sources":["../../../../src/compat/web-ifc/store_preview_channel.ts"],"names":[],"mappings":"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"}
|