@hviana/sema 0.4.3 → 0.4.4
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/dist/src/mind/bridge.js +46 -21
- package/dist/src/mind/mind.js +11 -2
- package/package.json +1 -1
- package/src/mind/bridge.ts +55 -18
- package/src/mind/mind.ts +11 -2
package/dist/src/mind/bridge.js
CHANGED
|
@@ -553,30 +553,54 @@ async function bridgeImpl(ctx, query, proposed) {
|
|
|
553
553
|
// hundreds of roots), so this is where its proposals are first sized.
|
|
554
554
|
//
|
|
555
555
|
// Candidate bytes are read LAZILY — on first access during the seed
|
|
556
|
-
// check — not eagerly for every collected id.
|
|
557
|
-
// the
|
|
558
|
-
//
|
|
559
|
-
//
|
|
560
|
-
//
|
|
561
|
-
//
|
|
562
|
-
//
|
|
563
|
-
//
|
|
564
|
-
//
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
556
|
+
// check — not eagerly for every collected id. Most climb-proposed
|
|
557
|
+
// candidates fail the seed check and never reach the expensive identity
|
|
558
|
+
// and frame-consensus gates.
|
|
559
|
+
//
|
|
560
|
+
// Frame unanimity is different: once any candidate reaches that gate, it
|
|
561
|
+
// must be evaluated against the COMPLETE collected candidate population,
|
|
562
|
+
// not only the prefix whose bytes happened to be loaded earlier. The full
|
|
563
|
+
// phrase-scale population is therefore materialised once, lazily, on the
|
|
564
|
+
// first unanimous() call and reused afterward.
|
|
565
|
+
//
|
|
566
|
+
// Null results are memoised too, so an empty or over-cap candidate is never
|
|
567
|
+
// read repeatedly by the candidate loop and the population materialiser.
|
|
568
|
+
const candidateByteMemo = new Map();
|
|
569
|
+
/** Read one candidate at most once. Returns null when it exceeds the
|
|
570
|
+
* phrase-scale cap or has no content. */
|
|
569
571
|
const bytesOfCandidate = (sid) => {
|
|
570
|
-
const
|
|
571
|
-
if (
|
|
572
|
-
return
|
|
572
|
+
const cached = candidateByteMemo.get(sid);
|
|
573
|
+
if (cached !== undefined)
|
|
574
|
+
return cached;
|
|
573
575
|
const b = candidateBytes(sid);
|
|
574
|
-
|
|
575
|
-
seededBytes.set(sid, b);
|
|
576
|
+
candidateByteMemo.set(sid, b);
|
|
576
577
|
return b;
|
|
577
578
|
};
|
|
578
|
-
|
|
579
|
-
|
|
579
|
+
let framePopulation = null;
|
|
580
|
+
/** Return the complete phrase-scale candidate population.
|
|
581
|
+
*
|
|
582
|
+
* This is intentionally lazy: queries that never reach frame unanimity
|
|
583
|
+
* keep the cheap per-candidate seed path. Once required, every candidate
|
|
584
|
+
* is bounded by candidateBytes(), loaded at most once, and all subsequent
|
|
585
|
+
* unanimity checks observe the same order-independent population.
|
|
586
|
+
*/
|
|
587
|
+
const ensureFramePopulation = () => {
|
|
588
|
+
if (framePopulation !== null) {
|
|
589
|
+
return framePopulation;
|
|
590
|
+
}
|
|
591
|
+
const complete = new Map();
|
|
592
|
+
for (const sid of candidates) {
|
|
593
|
+
const bytes = bytesOfCandidate(sid);
|
|
594
|
+
if (bytes !== null) {
|
|
595
|
+
complete.set(sid, bytes);
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
framePopulation = complete;
|
|
599
|
+
if (diagnostics) {
|
|
600
|
+
diagnostics.phraseScale = complete.size;
|
|
601
|
+
}
|
|
602
|
+
return complete;
|
|
603
|
+
};
|
|
580
604
|
// FRAME UNANIMITY: a substitution U → C inside the frame (Lf, Rf) is
|
|
581
605
|
// groundable only when the collected candidates — the store's own sample
|
|
582
606
|
// of contexts sharing the query's content — are unanimous about the
|
|
@@ -595,7 +619,8 @@ async function bridgeImpl(ctx, query, proposed) {
|
|
|
595
619
|
// the substitution was accepted). "Unanimous" must mean the store's own
|
|
596
620
|
// instances agree, which requires at least one instance to consult.
|
|
597
621
|
const unanimous = (u, c, lf, rf) => {
|
|
598
|
-
|
|
622
|
+
const population = ensureFramePopulation();
|
|
623
|
+
for (const bytes of population.values()) {
|
|
599
624
|
let from = 0;
|
|
600
625
|
for (;;) {
|
|
601
626
|
const i = indexOf(bytes, lf, from);
|
package/dist/src/mind/mind.js
CHANGED
|
@@ -219,8 +219,17 @@ export class Mind {
|
|
|
219
219
|
// Inference is a pure function of cumulative bytes. Conversation
|
|
220
220
|
// boundaries remain persistence/API metadata and must not select a
|
|
221
221
|
// different mechanism path than respond() on the identical byte stream.
|
|
222
|
-
|
|
223
|
-
|
|
222
|
+
// answeredSpans and currentTurnStart ARE restored from the conversation,
|
|
223
|
+
// however — they are pure functions of the cumulative byte stream (the
|
|
224
|
+
// assistant's own prior replies, and where the current user turn starts,
|
|
225
|
+
// are deterministic given the full transcript). Without them confluence,
|
|
226
|
+
// cover, the weave, and the consensus climb treat prior assistant turns
|
|
227
|
+
// as fresh query content — re-deriving them as constraints, voting
|
|
228
|
+
// anchors, and alignment points.
|
|
229
|
+
this.answeredSpans = conv ? conv.answeredSpans : [];
|
|
230
|
+
this.currentTurnStart = conv && conv.boundaries.length > 0
|
|
231
|
+
? conv.boundaries[conv.boundaries.length - 1]
|
|
232
|
+
: 0;
|
|
224
233
|
this.canon = canon ?? null;
|
|
225
234
|
this.canonMemo = canon ? new Map() : null;
|
|
226
235
|
this._beginMeter();
|
package/package.json
CHANGED
package/src/mind/bridge.ts
CHANGED
|
@@ -594,27 +594,62 @@ async function bridgeImpl(
|
|
|
594
594
|
// hundreds of roots), so this is where its proposals are first sized.
|
|
595
595
|
//
|
|
596
596
|
// Candidate bytes are read LAZILY — on first access during the seed
|
|
597
|
-
// check — not eagerly for every collected id.
|
|
598
|
-
// the
|
|
599
|
-
//
|
|
600
|
-
//
|
|
601
|
-
//
|
|
602
|
-
//
|
|
603
|
-
//
|
|
604
|
-
//
|
|
605
|
-
//
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
597
|
+
// check — not eagerly for every collected id. Most climb-proposed
|
|
598
|
+
// candidates fail the seed check and never reach the expensive identity
|
|
599
|
+
// and frame-consensus gates.
|
|
600
|
+
//
|
|
601
|
+
// Frame unanimity is different: once any candidate reaches that gate, it
|
|
602
|
+
// must be evaluated against the COMPLETE collected candidate population,
|
|
603
|
+
// not only the prefix whose bytes happened to be loaded earlier. The full
|
|
604
|
+
// phrase-scale population is therefore materialised once, lazily, on the
|
|
605
|
+
// first unanimous() call and reused afterward.
|
|
606
|
+
//
|
|
607
|
+
// Null results are memoised too, so an empty or over-cap candidate is never
|
|
608
|
+
// read repeatedly by the candidate loop and the population materialiser.
|
|
609
|
+
const candidateByteMemo = new Map<number, Uint8Array | null>();
|
|
610
|
+
|
|
611
|
+
/** Read one candidate at most once. Returns null when it exceeds the
|
|
612
|
+
* phrase-scale cap or has no content. */
|
|
610
613
|
const bytesOfCandidate = (sid: number): Uint8Array | null => {
|
|
611
|
-
const
|
|
612
|
-
if (
|
|
614
|
+
const cached = candidateByteMemo.get(sid);
|
|
615
|
+
if (cached !== undefined) return cached;
|
|
616
|
+
|
|
613
617
|
const b = candidateBytes(sid);
|
|
614
|
-
|
|
618
|
+
candidateByteMemo.set(sid, b);
|
|
615
619
|
return b;
|
|
616
620
|
};
|
|
617
|
-
|
|
621
|
+
|
|
622
|
+
let framePopulation: Map<number, Uint8Array> | null = null;
|
|
623
|
+
|
|
624
|
+
/** Return the complete phrase-scale candidate population.
|
|
625
|
+
*
|
|
626
|
+
* This is intentionally lazy: queries that never reach frame unanimity
|
|
627
|
+
* keep the cheap per-candidate seed path. Once required, every candidate
|
|
628
|
+
* is bounded by candidateBytes(), loaded at most once, and all subsequent
|
|
629
|
+
* unanimity checks observe the same order-independent population.
|
|
630
|
+
*/
|
|
631
|
+
const ensureFramePopulation = (): ReadonlyMap<number, Uint8Array> => {
|
|
632
|
+
if (framePopulation !== null) {
|
|
633
|
+
return framePopulation;
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
const complete = new Map<number, Uint8Array>();
|
|
637
|
+
|
|
638
|
+
for (const sid of candidates) {
|
|
639
|
+
const bytes = bytesOfCandidate(sid);
|
|
640
|
+
if (bytes !== null) {
|
|
641
|
+
complete.set(sid, bytes);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
framePopulation = complete;
|
|
646
|
+
|
|
647
|
+
if (diagnostics) {
|
|
648
|
+
diagnostics.phraseScale = complete.size;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
return complete;
|
|
652
|
+
};
|
|
618
653
|
|
|
619
654
|
// FRAME UNANIMITY: a substitution U → C inside the frame (Lf, Rf) is
|
|
620
655
|
// groundable only when the collected candidates — the store's own sample
|
|
@@ -639,7 +674,9 @@ async function bridgeImpl(
|
|
|
639
674
|
lf: Uint8Array,
|
|
640
675
|
rf: Uint8Array,
|
|
641
676
|
): boolean => {
|
|
642
|
-
|
|
677
|
+
const population = ensureFramePopulation();
|
|
678
|
+
|
|
679
|
+
for (const bytes of population.values()) {
|
|
643
680
|
let from = 0;
|
|
644
681
|
for (;;) {
|
|
645
682
|
const i = indexOf(bytes, lf, from);
|
package/src/mind/mind.ts
CHANGED
|
@@ -482,8 +482,17 @@ export class Mind implements MindContext {
|
|
|
482
482
|
// Inference is a pure function of cumulative bytes. Conversation
|
|
483
483
|
// boundaries remain persistence/API metadata and must not select a
|
|
484
484
|
// different mechanism path than respond() on the identical byte stream.
|
|
485
|
-
|
|
486
|
-
|
|
485
|
+
// answeredSpans and currentTurnStart ARE restored from the conversation,
|
|
486
|
+
// however — they are pure functions of the cumulative byte stream (the
|
|
487
|
+
// assistant's own prior replies, and where the current user turn starts,
|
|
488
|
+
// are deterministic given the full transcript). Without them confluence,
|
|
489
|
+
// cover, the weave, and the consensus climb treat prior assistant turns
|
|
490
|
+
// as fresh query content — re-deriving them as constraints, voting
|
|
491
|
+
// anchors, and alignment points.
|
|
492
|
+
this.answeredSpans = conv ? conv.answeredSpans : [];
|
|
493
|
+
this.currentTurnStart = conv && conv.boundaries.length > 0
|
|
494
|
+
? conv.boundaries[conv.boundaries.length - 1]
|
|
495
|
+
: 0;
|
|
487
496
|
this.canon = canon ?? null;
|
|
488
497
|
this.canonMemo = canon ? new Map() : null;
|
|
489
498
|
this._beginMeter();
|