@gamaze/hicortex 0.22.0 → 0.22.2
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/assets/dashboard.html +209 -76
- package/dist/calibration.d.ts +92 -12
- package/dist/calibration.js +102 -15
- package/dist/classify-domains.js +6 -1
- package/dist/consolidate.js +87 -19
- package/dist/dashboard.d.ts +11 -0
- package/dist/dashboard.js +9 -0
- package/dist/db.js +74 -0
- package/dist/eval/decay-eval.d.ts +4 -2
- package/dist/eval/decay-eval.js +4 -4
- package/dist/eval/eval-clock.d.ts +32 -0
- package/dist/eval/eval-clock.js +47 -0
- package/dist/eval/graph-eval.d.ts +15 -2
- package/dist/eval/graph-eval.js +51 -5
- package/dist/eval/planted-eval.d.ts +4 -0
- package/dist/eval/planted-eval.js +27 -2
- package/dist/eval/planted-harness.d.ts +7 -0
- package/dist/eval/planted-harness.js +2 -0
- package/dist/eval/ranking-battery.d.ts +49 -2
- package/dist/eval/ranking-battery.js +110 -2
- package/dist/eval/ranking-eval.d.ts +26 -6
- package/dist/eval/ranking-eval.js +197 -34
- package/dist/eval/ranking-fixtures.d.ts +41 -1
- package/dist/eval/ranking-fixtures.js +261 -2
- package/dist/eval/recall-sweep.d.ts +7 -2
- package/dist/eval/recall-sweep.js +42 -13
- package/dist/eval/relevance-eval.d.ts +115 -1
- package/dist/eval/relevance-eval.js +318 -32
- package/dist/eval/run-eval.d.ts +7 -4
- package/dist/eval/run-eval.js +36 -9
- package/dist/mcp-server.js +37 -9
- package/dist/nightly.js +14 -0
- package/dist/recall-index.d.ts +46 -3
- package/dist/recall-index.js +83 -26
- package/dist/recall-precision.d.ts +212 -0
- package/dist/recall-precision.js +381 -0
- package/dist/retrieval.d.ts +34 -15
- package/dist/retrieval.js +132 -59
- package/dist/types.d.ts +7 -0
- package/package.json +1 -1
- package/server.json +3 -3
package/assets/dashboard.html
CHANGED
|
@@ -427,6 +427,24 @@
|
|
|
427
427
|
.rec-band{ position:absolute; inset:0; border-radius:4px; }
|
|
428
428
|
.rec-dot{ position:absolute; top:50%; transform:translate(-50%,-50%); width:11px; height:11px; border-radius:50%; background:var(--text); border:2px solid var(--panel); box-shadow:0 0 0 1px color-mix(in srgb, var(--text) 40%, transparent), 0 0 8px color-mix(in srgb, var(--text) 30%, transparent); }
|
|
429
429
|
.rec-foot{ display:flex; align-items:center; gap:7px; }
|
|
430
|
+
/* Memory Precision Level 1 (#476) — the pushed-index row: a compact
|
|
431
|
+
second line in the .csub scale (the sibling-rhythm ruling 2026-09-14:
|
|
432
|
+
the card keeps the shared .bseg gap rhythm, header → big → band →
|
|
433
|
+
index row → foot). Direction-only coloring: green at/above the echoed
|
|
434
|
+
recall floor, muted below (the index bar reads conservative); the
|
|
435
|
+
floor tick is amber like the pace marker. Theme tokens only — both
|
|
436
|
+
themes render from their own table, no JS colors here. */
|
|
437
|
+
.rec-l1{ display:block; font-size:10.5px; color:var(--dim); min-width:0; line-height:1.6; }
|
|
438
|
+
.rec-l1 .l1row{ white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
|
|
439
|
+
.rec-l1 .lbl{ display:none; } /* #476 rename: the three-bucket text is self-labeled */
|
|
440
|
+
.rec-l1 .l1bar{ position:relative; flex:1 1 46px; height:5px; border-radius:3px; background:var(--tbar-bg); min-width:36px; }
|
|
441
|
+
.rec-l1 .l1bar .l1-fill{ position:absolute; left:0; top:0; bottom:0; border-radius:3px; background:color-mix(in srgb, var(--green) 65%, transparent); }
|
|
442
|
+
.rec-l1.below .l1bar .l1-fill{ background:color-mix(in srgb, var(--dim) 55%, transparent); }
|
|
443
|
+
.rec-l1 .l1bar .l1-floor{ position:absolute; top:-2px; bottom:-2px; width:1px; background:var(--amber); }
|
|
444
|
+
.rec-l1 .l1txt{ color:var(--dim); overflow:hidden; text-overflow:ellipsis; font-size:10.5px; letter-spacing:-.01em; }
|
|
445
|
+
.rec-l1 b{ color:var(--green-mid); font-weight:600; }
|
|
446
|
+
.rec-l1.below b{ color:var(--dim); }
|
|
447
|
+
#rec-div{ color:var(--amber); overflow:hidden; text-overflow:ellipsis; }
|
|
430
448
|
.b-health{ display:flex; align-items:center; gap:7px; font-size:11px; color:var(--dim); white-space:nowrap; }
|
|
431
449
|
.dot{ width:6px; height:6px; border-radius:50%; background:var(--green); box-shadow:0 0 10px color-mix(in srgb, var(--green) 70%, transparent); animation:breathe 3.2s ease-in-out infinite; flex:none; }
|
|
432
450
|
.dot.blue{ background:var(--blue); box-shadow:0 0 10px color-mix(in srgb, var(--blue) 70%, transparent); }
|
|
@@ -1159,21 +1177,32 @@
|
|
|
1159
1177
|
<div class="csub" id="tok-sub"> </div>
|
|
1160
1178
|
<div id="tok-nights" aria-label="LLM tokens per nightly run this billing period"></div>
|
|
1161
1179
|
</div>
|
|
1162
|
-
<!--
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1180
|
+
<!-- Memory Precision (#476, owner retitle) — ONE card, two context
|
|
1181
|
+
levels. Level 2 (recall depth) keeps the #426 U-band + zone word +
|
|
1182
|
+
provisional-hover semantics; the marker/tooltip read the WINDOW
|
|
1183
|
+
ratio off D.memory_precision.level2 (a pre-#476 server has no block
|
|
1184
|
+
→ the headline ratio — today's rendering exactly). Level 1 (pushed
|
|
1185
|
+
index) is a compact second row: mean similarity of pushed lines to
|
|
1186
|
+
their prompt, with a floor marker at the echoed
|
|
1187
|
+
recall_min_similarity and muted below it (the index's bar reads
|
|
1188
|
+
conservative — its noise costs compound per prompt) + the
|
|
1189
|
+
redundancy share; direction-only coloring, NO verdict words (the
|
|
1190
|
+
#426 semantics ruling extended: similarity is
|
|
1191
|
+
conversation-dependent). Divergence count on the FACE, the ≤3
|
|
1192
|
+
titles hover-only (no memory lists on the main page — owner ruling
|
|
1193
|
+
2026-09-12; the header search panel is the list surface). The
|
|
1194
|
+
window rides the #452 selector via the echoed window_days — never
|
|
1195
|
+
hardcoded, never a second range control. -->
|
|
1172
1196
|
<div class="bseg" id="lim-rec">
|
|
1173
|
-
<div class="gh"><span class="t">
|
|
1197
|
+
<div class="gh"><span class="t">Memory Precision</span><span class="sub" id="rec-sub">uses per showing</span></div>
|
|
1174
1198
|
<div class="big"><b class="n rec-word" id="rec-zone">—</b></div>
|
|
1175
1199
|
<div class="rec-bandrow" id="rec-bandrow"><div class="rec-band" id="rec-band"></div><i class="rec-dot" id="rec-dot" hidden></i></div>
|
|
1176
|
-
<div class="
|
|
1200
|
+
<div class="rec-l1" id="rec-l1" hidden style="display:block">
|
|
1201
|
+
<div class="l1row" id="l1-rel"> </div>
|
|
1202
|
+
<div class="l1row" id="l1-rep"> </div>
|
|
1203
|
+
<div class="l1row" id="l1-off"> </div>
|
|
1204
|
+
</div>
|
|
1205
|
+
<div class="csub rec-foot"><span id="rec-div" hidden></span></div>
|
|
1177
1206
|
</div>
|
|
1178
1207
|
</div>
|
|
1179
1208
|
<!-- row 2 · ops & maturity — capture health · 30 nights · maturity split · model -->
|
|
@@ -1391,9 +1420,15 @@ function fmtTokens(n){
|
|
|
1391
1420
|
return String(n);
|
|
1392
1421
|
}
|
|
1393
1422
|
/* deterministic per-id randomness — the same memory always lands in the
|
|
1394
|
-
same place across reloads (positions are content of the field, not noise)
|
|
1423
|
+
same place across reloads (positions are content of the field, not noise).
|
|
1424
|
+
#465: the salt hashes at the FRONT (hash32(salt+':'+s)) — FNV-1a does not
|
|
1425
|
+
diffuse a trailing-byte difference, and salts 1/2/3 differ only in their
|
|
1426
|
+
last character, so the old trailing form coupled angle to radius at
|
|
1427
|
+
Pearson r=0.953 (four spiral arms per domain). Salt-first measures
|
|
1428
|
+
r=0.019 (noise). Positions shift once (hash-derived content), then
|
|
1429
|
+
re-stabilize. */
|
|
1395
1430
|
function hash32(s){ let h=2166136261; for(let i=0;i<s.length;i++){ h^=s.charCodeAt(i); h=Math.imul(h,16777619);} return h>>>0; }
|
|
1396
|
-
function rand01(s,salt){ return hash32(
|
|
1431
|
+
function rand01(s,salt){ return hash32(salt+':'+s)/4294967296; }
|
|
1397
1432
|
|
|
1398
1433
|
/* ---------- token handling (harvested verbatim from the 0.20.4 console:
|
|
1399
1434
|
?token= handoff stripped from the URL, localStorage persistence, 401 →
|
|
@@ -1482,8 +1517,11 @@ const DEPTH_BANDS = { truth:[.9,1.05], belief:[1.05,1.3], forming:[1.3,1.55], fa
|
|
|
1482
1517
|
post-backfill store still shows a visible gradient and the inflated
|
|
1483
1518
|
pre-#425 store shows no monsters. Robust by construction: the mapping is
|
|
1484
1519
|
absolute (no min/max over the live distribution), so it cannot explode on
|
|
1485
|
-
a skewed store. Pure functions — the ratio is behaviorally tested.
|
|
1486
|
-
|
|
1520
|
+
a skewed store. Pure functions — the ratio is behaviorally tested.
|
|
1521
|
+
#474 graph final (owner 2026-09-19): the balls at 30% — 1.8→2.7, exactly
|
|
1522
|
+
0.30× of the 6→9 law; the depth divisor and the ruled ratio band are
|
|
1523
|
+
scale-invariant and unchanged. */
|
|
1524
|
+
function bubbleRadius(s){ return 1.8 + Math.sqrt(clamp(s??0,0,1))*0.9; }
|
|
1487
1525
|
function depthSizeDivisor(dz){ return Math.pow(Math.max(.14,dz),0.35); }
|
|
1488
1526
|
|
|
1489
1527
|
/* ---------- live-data state ---------- */
|
|
@@ -1500,7 +1538,7 @@ let TOTAL=0, removedNow=0;
|
|
|
1500
1538
|
clock (owner ruling 2026-09-13; only the boot reveal counts up) */
|
|
1501
1539
|
|
|
1502
1540
|
/* =====================================================================
|
|
1503
|
-
WORLD — domains, memories
|
|
1541
|
+
WORLD — domains, memories, the dateline window (the visible set), real
|
|
1504
1542
|
links, the replay ledger. All positions derive from id hashes → stable
|
|
1505
1543
|
across reloads and across the refreshes after Update/Remove.
|
|
1506
1544
|
===================================================================== */
|
|
@@ -1509,8 +1547,14 @@ const PORT = [ [.50,.20,.15],[.28,.38,.12],[.74,.40,.12],[.50,.62,.13],[.25,.68,
|
|
|
1509
1547
|
let DOMAINS = []; // {name,count,land,port,cx,cy,cr}
|
|
1510
1548
|
const mems = new Map(); // id -> memory object (live + replay ghosts)
|
|
1511
1549
|
const links = []; // real link edges, engine-decorated
|
|
1512
|
-
const bubbles = []; // the ~120-mem interactive importance sample
|
|
1513
1550
|
let crowdByStage = {}; // stage -> [mem refs] (EVERY memory paints)
|
|
1551
|
+
const bubbles = []; // the latest-N-by-dateline visible set (#474
|
|
1552
|
+
// return; owned by refreshWindow, rebuilt on T)
|
|
1553
|
+
const FIELD_WINDOW_N = 1000; // #474 graph final (owner 2026-09-19): the field shows the latest N memories by dateline
|
|
1554
|
+
let WIN_ORDER = []; // every mem (live + ghosts), effCreated DESC, id ASC
|
|
1555
|
+
let winSet = new Set(); // ids in the window at the current T
|
|
1556
|
+
let winCount = []; // per-domain window counts (labels + tip)
|
|
1557
|
+
let winT = -1;
|
|
1514
1558
|
let byAgentCounts = {}; // source_agent -> count
|
|
1515
1559
|
let CONTEXTS = []; // [{id,name,machine,count}] — #421 machine × harness grouping
|
|
1516
1560
|
let adj = new Map(); // id -> [neighbor ids] (real links)
|
|
@@ -1519,6 +1563,13 @@ let learnedL = [], mergedL = [], enrichedL = [];
|
|
|
1519
1563
|
let NIGHTS = []; // the events payload's night list
|
|
1520
1564
|
let WINDOW = 1, NOW_T = .999, REPLAY_OK = false;
|
|
1521
1565
|
|
|
1566
|
+
/* Replay pacing (owner 2026-09-19: 2x faster default). Event-driven cruise:
|
|
1567
|
+
each ledger event lands every REPLAY_TICK_MS; a heralded (birth/merge)
|
|
1568
|
+
event holds the clock REPLAY_HERALD_MS then applies; boundary beats rest
|
|
1569
|
+
REPLAY_REST_MS. Halve all three to run 2x; the constants are the only
|
|
1570
|
+
pacing surface. */
|
|
1571
|
+
const REPLAY_TICK_MS=205, REPLAY_HERALD_MS=108, REPLAY_REST_MS=800;
|
|
1572
|
+
|
|
1522
1573
|
function domIndex(domain){ const i = DOMAINS.findIndex(d=>d.name===domain); return i<0?0:i; }
|
|
1523
1574
|
function titleOf(id){ const m=mems.get(id); return m?m.title:'(absorbed)'; }
|
|
1524
1575
|
|
|
@@ -1583,6 +1634,10 @@ function buildWorld(){
|
|
|
1583
1634
|
if(!m.ghost && !keep.has(id)) mems.delete(id);
|
|
1584
1635
|
}
|
|
1585
1636
|
|
|
1637
|
+
// the crowd: EVERY memory, bucketed by stage for one fillStyle per pass
|
|
1638
|
+
crowdByStage = { forming:[], belief:[], truth:[], fading:[] };
|
|
1639
|
+
for(const m of mems.values()) (crowdByStage[m.stage]||crowdByStage.forming).push(m);
|
|
1640
|
+
|
|
1586
1641
|
// replay metadata from the events ledger: in-window births + merge-outs
|
|
1587
1642
|
// (absorbed losers get ghost entries so their merge animation has a
|
|
1588
1643
|
// position and their birth a bloom — they are not part of the live field).
|
|
@@ -1651,34 +1706,12 @@ function buildWorld(){
|
|
|
1651
1706
|
}
|
|
1652
1707
|
}
|
|
1653
1708
|
|
|
1654
|
-
//
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
//
|
|
1659
|
-
|
|
1660
|
-
// (largest-remainder to the fixed total, minimum 1 each), each quota filled
|
|
1661
|
-
// by that stage's OWN strength→access ranking with an id-ASC tie-break —
|
|
1662
|
-
// fully deterministic, no Math.random. The old global top-120-by-strength
|
|
1663
|
-
// sample was 100% truth BY CONSTRUCTION (truth IS the top strength band),
|
|
1664
|
-
// so every touchable dot read green and the 1–2px crowd was visually
|
|
1665
|
-
// negligible; on an even store this yields ~30/30/30/30.
|
|
1666
|
-
bubbles.length = 0;
|
|
1667
|
-
{
|
|
1668
|
-
const BUBBLE_N=120;
|
|
1669
|
-
const stageArrs=STAGE_KEYS.map(k=>crowdByStage[k].filter(m=>!m.ghost)
|
|
1670
|
-
.sort((a,b)=> b.strength-a.strength || b.access-a.access || (a.id<b.id?-1:a.id>b.id?1:0)));
|
|
1671
|
-
const liveCount=stageArrs.reduce((n,a)=>n+a.length,0);
|
|
1672
|
-
if(liveCount>0){
|
|
1673
|
-
const exact=stageArrs.map(a=>a.length/liveCount*BUBBLE_N);
|
|
1674
|
-
const quota=exact.map(Math.floor);
|
|
1675
|
-
for(let i=0;i<quota.length;i++) if(quota[i]===0&&stageArrs[i].length>0) quota[i]=1;
|
|
1676
|
-
let left=BUBBLE_N-quota.reduce((n,q)=>n+q,0);
|
|
1677
|
-
const order=exact.map((_,i)=>i).sort((a,b)=>(exact[b]%1)-(exact[a]%1)); // remainder DESC, stage order tie
|
|
1678
|
-
for(let oi=0; left>0; oi++, left--) quota[order[oi%order.length]]++;
|
|
1679
|
-
stageArrs.forEach((a,i)=>{ bubbles.push(...a.slice(0,Math.min(quota[i],a.length))); });
|
|
1680
|
-
}
|
|
1681
|
-
}
|
|
1709
|
+
// #474 return: the visible set is the dateline WINDOW, not a sample —
|
|
1710
|
+
// WIN_ORDER walks every mem (live + ghosts) newest-first (effCreated DESC,
|
|
1711
|
+
// id ASC tie-break; ghosts sort via their birth night's date), and
|
|
1712
|
+
// refreshWindow (draw) slices the latest FIELD_WINDOW_N alive-at-T rows
|
|
1713
|
+
// out of it each time T moves.
|
|
1714
|
+
WIN_ORDER = Array.from(mems.values()).sort(winCmp);
|
|
1682
1715
|
|
|
1683
1716
|
// contexts (source_agent values) with their machine stamps (#421 machine ×
|
|
1684
1717
|
// harness): the rail + capture card group on (machine ?? legacy) × harness.
|
|
@@ -1740,6 +1773,31 @@ function aliveAt(b,t){
|
|
|
1740
1773
|
return true;
|
|
1741
1774
|
}
|
|
1742
1775
|
function dateAt(t){ const i=clamp(Math.floor(t),0,NIGHTS.length-1); return NIGHTS[i]?NIGHTS[i].date:''; }
|
|
1776
|
+
/* #474 return: the visible set is a DATELINE WINDOW — at replay clock T the
|
|
1777
|
+
field draws the latest FIELD_WINDOW_N memories by effective created date
|
|
1778
|
+
(created_at; ghosts via their birth night), not a sample and not the whole
|
|
1779
|
+
store. Pure helpers (behaviorally tested). */
|
|
1780
|
+
function effCreated(m){ return m.created || (m.born>=0 ? dateAt(m.born) : ''); }
|
|
1781
|
+
function windowPick(order, t, n, dl, isNow){
|
|
1782
|
+
const out=[];
|
|
1783
|
+
for(const m of order){
|
|
1784
|
+
if(out.length>=n) break;
|
|
1785
|
+
if(!aliveAt(m,t)) continue;
|
|
1786
|
+
if(!isNow && m.born<0 && effCreated(m)>dl) continue; // untracked + newer than the dateline
|
|
1787
|
+
out.push(m);
|
|
1788
|
+
}
|
|
1789
|
+
return out;
|
|
1790
|
+
}
|
|
1791
|
+
function winCmp(a,b){ return effCreated(b)<effCreated(a)?-1: effCreated(b)>effCreated(a)?1: a.id<b.id?-1:1; }
|
|
1792
|
+
function refreshWindow(t){
|
|
1793
|
+
if(t===winT) return;
|
|
1794
|
+
winT=t;
|
|
1795
|
+
const picked = windowPick(WIN_ORDER, t, FIELD_WINDOW_N, dateAt(t), t>=NOW_T);
|
|
1796
|
+
winSet = new Set(picked.map(m=>m.id));
|
|
1797
|
+
winCount = new Array(DOMAINS.length).fill(0);
|
|
1798
|
+
for(const m of picked) winCount[m.dom]++;
|
|
1799
|
+
bubbles.length=0; bubbles.push(...picked);
|
|
1800
|
+
}
|
|
1743
1801
|
|
|
1744
1802
|
/* =====================================================================
|
|
1745
1803
|
THEME — one engine, two palettes. Dark (the brand night: glow) is the
|
|
@@ -1897,22 +1955,16 @@ function sprite(stage, r){
|
|
|
1897
1955
|
const st = PAL.stages[stage] || PAL.stages.forming;
|
|
1898
1956
|
const rgb = st.rgb;
|
|
1899
1957
|
if(PAL.name==='dark'){
|
|
1958
|
+
/* #474 final polish (owner 2026-09-20): plain dot — no glow halo, no
|
|
1959
|
+
white core gradient. A filled circle with a slightly brighter edge;
|
|
1960
|
+
the maturity color carries the reading, the size stays small. */
|
|
1900
1961
|
const S = Math.ceil(rad*PAL.sprK), c2 = document.createElement('canvas');
|
|
1901
1962
|
c2.width=S; c2.height=S;
|
|
1902
1963
|
const g = c2.getContext('2d'), cxp=S/2;
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
g.fillStyle=gr; g.fillRect(0,0,S,S);
|
|
1908
|
-
gr = g.createRadialGradient(cxp-rad*.28,cxp-rad*.32,rad*.1, cxp,cxp,rad);
|
|
1909
|
-
gr.addColorStop(0,'rgba(255,255,255,'+(.5*st.alpha)+')');
|
|
1910
|
-
gr.addColorStop(.35, rgba(rgb,.55*st.alpha));
|
|
1911
|
-
gr.addColorStop(.82, rgba(rgb,.22*st.alpha));
|
|
1912
|
-
gr.addColorStop(1, rgba(rgb,.04));
|
|
1913
|
-
g.fillStyle=gr; g.beginPath(); g.arc(cxp,cxp,rad,0,7); g.fill();
|
|
1914
|
-
g.strokeStyle=rgba(rgb,.34*st.alpha); g.lineWidth=1;
|
|
1915
|
-
g.beginPath(); g.arc(cxp,cxp,rad-.5,0,7); g.stroke();
|
|
1964
|
+
g.fillStyle=rgba(rgb,.88*st.alpha);
|
|
1965
|
+
g.beginPath(); g.arc(cxp,cxp,rad*.82,0,7); g.fill();
|
|
1966
|
+
g.strokeStyle=rgba(rgb,.45*st.alpha); g.lineWidth=1;
|
|
1967
|
+
g.beginPath(); g.arc(cxp,cxp,rad*.82,0,7); g.stroke();
|
|
1916
1968
|
/* #422 round 2: fading's DISTINCT outer ring — the rim stage's fill runs
|
|
1917
1969
|
at low alpha by design; without its own edge treatment the dots were
|
|
1918
1970
|
illegible against the night ground */
|
|
@@ -1995,7 +2047,7 @@ function buildPaths(){
|
|
|
1995
2047
|
}
|
|
1996
2048
|
}
|
|
1997
2049
|
function pathAlive(p,t){
|
|
1998
|
-
for(const id of p.nodes){ const b=mems.get(id); if(!b||!aliveAt(b,t)) return false; }
|
|
2050
|
+
for(const id of p.nodes){ const b=mems.get(id); if(!b||!aliveAt(b,t)||!winSet.has(id)) return false; }
|
|
1999
2051
|
return t>=p.born;
|
|
2000
2052
|
}
|
|
2001
2053
|
function spawnSignal(showcase){
|
|
@@ -2054,8 +2106,10 @@ function advanceSignals(now, dt){
|
|
|
2054
2106
|
}
|
|
2055
2107
|
|
|
2056
2108
|
/* =====================================================================
|
|
2057
|
-
THE FRAME — theme-aware;
|
|
2058
|
-
|
|
2109
|
+
THE FRAME — theme-aware; synapses, signals, bubbles (painter-sorted
|
|
2110
|
+
far→near), waymarkers, furniture. #474 return: the ONLY dots drawn are
|
|
2111
|
+
the dateline window (latest FIELD_WINDOW_N by effective created date at
|
|
2112
|
+
the replay clock — see refreshWindow); no crowd pass, no sample.
|
|
2059
2113
|
===================================================================== */
|
|
2060
2114
|
let labelRects=[];
|
|
2061
2115
|
/* emergence queue (#422 live review): a night's births/links become VISIBLE
|
|
@@ -2099,6 +2153,7 @@ function processEmergence(t){
|
|
|
2099
2153
|
}
|
|
2100
2154
|
function draw(now, dt){
|
|
2101
2155
|
const t=T;
|
|
2156
|
+
refreshWindow(t); // #474: the visible set = latest-N by dateline at this T (bubbles, winSet, winCount)
|
|
2102
2157
|
const dark = PAL.name==='dark';
|
|
2103
2158
|
const ADD = dark ? 'lighter' : 'source-over';
|
|
2104
2159
|
ctx.clearRect(0,0,view.w,view.h);
|
|
@@ -2164,6 +2219,12 @@ function draw(now, dt){
|
|
|
2164
2219
|
}
|
|
2165
2220
|
ctx.globalAlpha=1;
|
|
2166
2221
|
|
|
2222
|
+
/* emergence flags resolve FIRST (once per frame) — the visible set and
|
|
2223
|
+
the link pass below read them; dots still queued (_emerged===false)
|
|
2224
|
+
stay invisible until their frame budget comes up. (#474: the old
|
|
2225
|
+
every-memory crowd pass is gone — the window IS the field.) */
|
|
2226
|
+
processEmergence(t);
|
|
2227
|
+
|
|
2167
2228
|
/* THE CROWD — every memory in the store as maturity-colored micro-stars
|
|
2168
2229
|
behind the touchable sample (no sampling: the dot count IS the store).
|
|
2169
2230
|
One fillStyle per stage pass. The emergence queue is resolved FIRST
|
|
@@ -2181,7 +2242,7 @@ function draw(now, dt){
|
|
|
2181
2242
|
if(fog<.15) continue;
|
|
2182
2243
|
const [sx,sy]=proj3(m.nx||.5,m.ny||.5,dz);
|
|
2183
2244
|
if(sx<-2||sy<-2||sx>view.w+2||sy>view.h+2) continue;
|
|
2184
|
-
ctx.globalAlpha=fog*.5;
|
|
2245
|
+
ctx.globalAlpha=fog*.5*(focusDom!=null&&m.dom!==focusDom?.15:1);
|
|
2185
2246
|
const px=Math.max(1,Math.round((rand01(m.id,9)<.85?1:1.8)/dz*1.4));
|
|
2186
2247
|
ctx.fillRect(sx,sy,px,px);
|
|
2187
2248
|
}
|
|
@@ -2235,6 +2296,7 @@ function draw(now, dt){
|
|
|
2235
2296
|
if(L.rk>=lodK) continue; // zoom LOD (lines only)
|
|
2236
2297
|
const a=mems.get(L.a), b=mems.get(L.b);
|
|
2237
2298
|
if(!a||!b||!aliveAt(a,t)||!aliveAt(b,t)) continue;
|
|
2299
|
+
/* #474 final polish: the both-endpoints-in-window gate killed the mesh — links draw between ANY placed memories (bedrock parity: the full LOD-tamed mesh), endpoints carry positions regardless of window membership */
|
|
2238
2300
|
if(a._emerged===false||b._emerged===false) continue; // thread waits for both endpoints
|
|
2239
2301
|
const [ax,ay]=bpos(a,now,t), [bx,by]=bpos(b,now,t);
|
|
2240
2302
|
const ctrl=segCtrlN(ax,ay,bx,by,(L.use>18?1:-1));
|
|
@@ -2249,6 +2311,9 @@ function draw(now, dt){
|
|
|
2249
2311
|
const prog = L.forming ? clamp((t-(L._emergeT!==undefined?L._emergeT:L.born))/1.4,0,1) : 1;
|
|
2250
2312
|
const drawP=Math.min(prog,linkBoot);
|
|
2251
2313
|
if(drawP<=0) continue;
|
|
2314
|
+
/* #474 final polish: domain focus — a thread stays lit only if an
|
|
2315
|
+
endpoint belongs to the focused domain (owner 2026-09-20) */
|
|
2316
|
+
const focusDim = (focusDom!=null && a.dom!==focusDom && b.dom!==focusDom) ? .15 : 1;
|
|
2252
2317
|
const len=Math.hypot(x2-x1,y2-y1)*1.15;
|
|
2253
2318
|
const superFam = L.rel==='superseded_by'||L.rel==='corrected_by';
|
|
2254
2319
|
/* fix-round-3 weights: settled alphas roughly halved (both themes) so the
|
|
@@ -2256,7 +2321,7 @@ function draw(now, dt){
|
|
|
2256
2321
|
const bright=(a.stage==='truth'||b.stage==='truth') ? (dark?.07:.11) : (dark?.035:.06);
|
|
2257
2322
|
const baseW=.34+useF*.55+heat*.5;
|
|
2258
2323
|
/* the SETTLED stroke is always the base */
|
|
2259
|
-
ctx.strokeStyle=rgba(PAL.thread,(bright*(superFam?.45:1)+useF*(dark?.05:.07)+heat*.28)*linkBoot*tfog);
|
|
2324
|
+
ctx.strokeStyle=rgba(PAL.thread,(bright*(superFam?.45:1)+useF*(dark?.05:.07)+heat*.28)*linkBoot*tfog*focusDim);
|
|
2260
2325
|
ctx.lineWidth=baseW;
|
|
2261
2326
|
ctx.setLineDash(superFam?[4,4]:[len*drawP,1e5]);
|
|
2262
2327
|
ctx.beginPath(); ctx.moveTo(x1,y1); ctx.quadraticCurveTo(cx1,cy1,x2,y2); ctx.stroke();
|
|
@@ -2265,7 +2330,7 @@ function draw(now, dt){
|
|
|
2265
2330
|
in the same proportion as the settled stroke) */
|
|
2266
2331
|
const settle=1-prog;
|
|
2267
2332
|
const baseA=(dark? .07 : .09)+((dark?.15:.17)-(dark?.07:.09))*drawP;
|
|
2268
|
-
ctx.strokeStyle=rgba(PAL.threadHot,(baseA+.14*heat)*tfog*(superFam?.5:1)*settle);
|
|
2333
|
+
ctx.strokeStyle=rgba(PAL.threadHot,(baseA+.14*heat)*tfog*(superFam?.5:1)*settle*focusDim);
|
|
2269
2334
|
ctx.lineWidth=baseW+(.18+drawP*.3)*settle;
|
|
2270
2335
|
ctx.setLineDash(superFam?[4,4]:[len*drawP,1e5]);
|
|
2271
2336
|
ctx.beginPath(); ctx.moveTo(x1,y1); ctx.quadraticCurveTo(cx1,cy1,x2,y2); ctx.stroke();
|
|
@@ -2340,8 +2405,9 @@ function draw(now, dt){
|
|
|
2340
2405
|
dark-blue-on-near-black at ~4px read invisible to a vision model);
|
|
2341
2406
|
the projection factor is known here, and far-stage bubbles (rim depth
|
|
2342
2407
|
/ small viewports) were collapsing to ~1-2px. Every stage stays a
|
|
2343
|
-
legible glimmer; ordering untouched.
|
|
2344
|
-
|
|
2408
|
+
legible glimmer; ordering untouched. #474 graph final: floor 1.5 —
|
|
2409
|
+
0.30× of 5, proportional with the 30% balls. */
|
|
2410
|
+
r=Math.max(r,1.5);
|
|
2345
2411
|
let remA=1;
|
|
2346
2412
|
if(b.removing){ const p=clamp((now-b.removing)/700,0,1); remA=1-p; if(p>=1){ b.removed=true; b.removing=undefined; } }
|
|
2347
2413
|
const ex=b._ex||0;
|
|
@@ -2441,8 +2507,11 @@ function draw(now, dt){
|
|
|
2441
2507
|
ctx.font=(9.5*k).toFixed(1)+'px '+FF;
|
|
2442
2508
|
try{ ctx.letterSpacing=(1*k).toFixed(1)+'px'; }catch(e){}
|
|
2443
2509
|
ctx.fillStyle= dark? 'rgba(90,90,90,'+(.85*dimming*lp)+')' : hexA(PAL.labelCount,dimming*lp);
|
|
2444
|
-
|
|
2445
|
-
|
|
2510
|
+
/* #474: the label count is the WINDOW count (what is drawn at this T),
|
|
2511
|
+
not the store total — honest with the dateline view. */
|
|
2512
|
+
const cnt=fmt(winCount[i]||0);
|
|
2513
|
+
ctx.fillText(cnt, sx+w+9*k, sy);
|
|
2514
|
+
const bw=w+9*k+ctx.measureText(cnt).width;
|
|
2446
2515
|
ctx.strokeStyle= active? rgba(PAL.stages.truth.rgb,.55*lp) : (dark? 'rgba(120,130,140,'+(.4*dimming*lp)+')' : 'rgba(96,92,78,'+(.5*dimming*lp)+')');
|
|
2447
2516
|
ctx.lineWidth=1;
|
|
2448
2517
|
const bx=sx-9*k, by=sy-11*k, bxx=bx+bw+9*k, byy=by+15*k, tk=4*k;
|
|
@@ -2607,18 +2676,18 @@ function autoTick(now){
|
|
|
2607
2676
|
if(T>=NOW_T-.001){
|
|
2608
2677
|
/* a beat at "now": re-kick to the range start ONLY before the first
|
|
2609
2678
|
full playback; after it, REST here — plays once, never loops (#452) */
|
|
2610
|
-
if(played){ autoPlay=false; autoNextAt=now+
|
|
2611
|
-
autoEvIdx=0; autoNextAt=now+
|
|
2679
|
+
if(played){ autoPlay=false; autoNextAt=now+REPLAY_REST_MS; return; }
|
|
2680
|
+
autoEvIdx=0; autoNextAt=now+REPLAY_REST_MS; seek(.001); return;
|
|
2612
2681
|
}
|
|
2613
2682
|
while(autoEvIdx<EVENTS.length && EVENTS[autoEvIdx].t<=T+.0001) autoEvIdx++;
|
|
2614
2683
|
if(autoEvIdx>=EVENTS.length){
|
|
2615
2684
|
/* ledger exhausted: arrive at today and complete the playback (the
|
|
2616
2685
|
flags go BEFORE the seek so onTChanged's control swap sees them) */
|
|
2617
|
-
autoNextAt=now+
|
|
2686
|
+
autoNextAt=now+REPLAY_REST_MS; played=true; autoPlay=false; seek(WINDOW); return;
|
|
2618
2687
|
}
|
|
2619
2688
|
const ev=EVENTS[autoEvIdx++];
|
|
2620
|
-
if(ev.id && signals.length<8){ heraldTo(ev.id); pendingApply={t:ev.t+.001, at:now+
|
|
2621
|
-
else { seek(ev.t+.001); autoNextAt=now+
|
|
2689
|
+
if(ev.id && signals.length<8){ heraldTo(ev.id); pendingApply={t:ev.t+.001, at:now+REPLAY_HERALD_MS}; }
|
|
2690
|
+
else { seek(ev.t+.001); autoNextAt=now+REPLAY_TICK_MS; }
|
|
2622
2691
|
}
|
|
2623
2692
|
track.addEventListener('pointerdown',e=>{ if(!REPLAY_OK) return; scrubbing=true; manualTake(); track.setPointerCapture(e.pointerId); seek(trackFrac(e)*WINDOW); });
|
|
2624
2693
|
track.addEventListener('pointermove',e=>{ if(scrubbing) seek(trackFrac(e)*WINDOW); });
|
|
@@ -2835,7 +2904,8 @@ cv.addEventListener('pointermove',e=>{
|
|
|
2835
2904
|
tip.style.display='block';
|
|
2836
2905
|
tip.style.left=Math.min(e.clientX+14,window.innerWidth-300)+'px';
|
|
2837
2906
|
tip.style.top=(e.clientY+16)+'px';
|
|
2838
|
-
|
|
2907
|
+
/* #474: the window count at this T — honest with what is drawn */
|
|
2908
|
+
tip.innerHTML='<b>'+esc(d.name)+'</b><span style="color:var(--dim)">'+fmt(winCount[lb]||0)+' in view</span>';
|
|
2839
2909
|
}else tip.style.display='none';
|
|
2840
2910
|
dirty=true;
|
|
2841
2911
|
});
|
|
@@ -3174,7 +3244,14 @@ function recallGradAt(frac,z,theme){
|
|
|
3174
3244
|
}
|
|
3175
3245
|
let lastRecUses=null; /* setTheme's re-render carries the last value */
|
|
3176
3246
|
function renderRecBand(ups){
|
|
3247
|
+
/* #476: the marker/tooltip read the WINDOW ratio when the memory_precision
|
|
3248
|
+
block is present; a pre-#476 server (no block) degrades to the headline
|
|
3249
|
+
ratio — today's rendering exactly (the capture card's block-absence
|
|
3250
|
+
guard pattern). A null window value honestly renders "—" below. */
|
|
3251
|
+
const mp=D&&D.memory_precision?D.memory_precision:null;
|
|
3252
|
+
if(mp&&mp.level2) ups=mp.level2.uses_per_showing;
|
|
3177
3253
|
lastRecUses=ups;
|
|
3254
|
+
renderRecL1(mp);
|
|
3178
3255
|
const z=F&&F.thresholds?F.thresholds.recall_uses:null;
|
|
3179
3256
|
const axis=z&&typeof z.axis_max==='number'&&z.axis_max>0?z.axis_max:null;
|
|
3180
3257
|
const row=el('rec-bandrow'), band=el('rec-band'), dot=el('rec-dot'), word=el('rec-zone');
|
|
@@ -3198,7 +3275,7 @@ function renderRecBand(ups){
|
|
|
3198
3275
|
if(zk){
|
|
3199
3276
|
dot.hidden=false;
|
|
3200
3277
|
dot.style.left=pct(ups)+'%';
|
|
3201
|
-
dot.title=ups.toFixed(3)+' uses per showing — last 30
|
|
3278
|
+
dot.title=ups.toFixed(3)+' uses per showing — last '+(mp&&mp.window_days?mp.window_days:30)+' days';
|
|
3202
3279
|
word.textContent=RECALL_ZONE_WORD[zk];
|
|
3203
3280
|
word.className='n rec-word';
|
|
3204
3281
|
/* the big word's color = the gradient sampled AT the marker — the word
|
|
@@ -3226,6 +3303,62 @@ function renderRecBand(ups){
|
|
|
3226
3303
|
}
|
|
3227
3304
|
}
|
|
3228
3305
|
|
|
3306
|
+
/* ---------- Memory Precision — Level 1, the pushed index (#476). A compact
|
|
3307
|
+
second row beside Level 2's U-band: mean similarity of pushed lines to
|
|
3308
|
+
their prompt (a 0..1 bar with a floor tick at the /dashboard/field echo of
|
|
3309
|
+
recall_min_similarity — the server's own recall floor, never a page
|
|
3310
|
+
literal), muted below the floor (the index row reads conservative: its
|
|
3311
|
+
noise lands on every prompt), plus the redundancy share (lines restating
|
|
3312
|
+
the session's standing context at/above the echoed cosine). Direction-only
|
|
3313
|
+
coloring, NO verdict words — the #426 semantics ruling extended.
|
|
3314
|
+
Divergence: the COUNT on the card face, the ≤3 titles hover-only (no
|
|
3315
|
+
memory lists on the main page, owner 2026-09-12 — the search panel is the
|
|
3316
|
+
list surface). Absent block (pre-#476 server) → the whole row hides and
|
|
3317
|
+
the sub keeps the old label — today's rendering exactly. */
|
|
3318
|
+
function renderRecL1(mp){
|
|
3319
|
+
const row=el('rec-l1'), sub=el('rec-sub'), dv=el('rec-div');
|
|
3320
|
+
if(!mp||!mp.level1||!mp.level2){
|
|
3321
|
+
row.hidden=true; dv.hidden=true; dv.title='';
|
|
3322
|
+
if(sub) sub.textContent='uses per showing';
|
|
3323
|
+
return;
|
|
3324
|
+
}
|
|
3325
|
+
if(sub) sub.textContent='last '+(mp.window_days||90)+' days';
|
|
3326
|
+
const l1=mp.level1;
|
|
3327
|
+
const floor=(F&&F.thresholds&&typeof F.thresholds.recall_min_similarity==='number')?F.thresholds.recall_min_similarity:null;
|
|
3328
|
+
const ra=(l1.thresholds&&typeof l1.thresholds.redundant_above==='number')?l1.thresholds.redundant_above:null;
|
|
3329
|
+
const mins=(l1.thresholds&&typeof l1.thresholds.divergence_min_shown==='number')?l1.thresholds.divergence_min_shown:5;
|
|
3330
|
+
const sim=(typeof l1.mean_similarity==='number'&&isFinite(l1.mean_similarity))?l1.mean_similarity:null;
|
|
3331
|
+
const red=(typeof l1.redundant_share==='number'&&isFinite(l1.redundant_share))?l1.redundant_share:null;
|
|
3332
|
+
if(sim===null){
|
|
3333
|
+
row.hidden=true; /* nothing measured in the window — the row degrades away */
|
|
3334
|
+
}else{
|
|
3335
|
+
row.hidden=false;
|
|
3336
|
+
row.classList.toggle('below',floor!==null&&sim<floor);
|
|
3337
|
+
/* numbers only on the face — direction carries the meaning, no verdict words */
|
|
3338
|
+
/* #476 owner rename (2026-09-20): the three buckets as named — Relevant /
|
|
3339
|
+
Repeated known / Off-target. Relevant = the mean relevance; Repeated =
|
|
3340
|
+
the redundant share; Off-target = the remainder (pushed lines that were
|
|
3341
|
+
neither relevant nor new). Numbers, no verdict words (#426). */
|
|
3342
|
+
const relPct=Math.round(clamp(sim,0,1)*100);
|
|
3343
|
+
const repPct=red!==null?Math.round(clamp(red,0,1)*100):0;
|
|
3344
|
+
const offPct=Math.max(0,100-relPct-repPct);
|
|
3345
|
+
const dv=mp.divergence, nUsed=(dv&&typeof dv.count==='number')?dv.count:0;
|
|
3346
|
+
el('l1-rel').innerHTML='<b>Relevant: '+relPct+'%</b>';
|
|
3347
|
+
el('l1-rep').textContent='Repeated known: '+repPct+'%';
|
|
3348
|
+
el('l1-off').textContent='Off-target: '+offPct+'%'+(nUsed>0?' ('+nUsed+' never used)':'');
|
|
3349
|
+
row.title='pushed index, last '+(mp.window_days||90)+' days — mean similarity of pushed lines to their prompt (tick at the recall floor '+
|
|
3350
|
+
(floor!==null?floor.toFixed(2):'—')+'; muted below it)'+
|
|
3351
|
+
(ra!==null?'; redundant = share of lines at ≥'+ra.toFixed(2)+' cosine vs the session\'s standing context (lessons + identity)':'')+
|
|
3352
|
+
' · '+fmt(l1.pushes)+' pushes, '+fmt(l1.lines)+' lines';
|
|
3353
|
+
}
|
|
3354
|
+
/* divergence — the face count is amber; the ≤3 lines ride the native
|
|
3355
|
+
tooltip ONLY (text via .title, never face content) */
|
|
3356
|
+
/* #476 owner bundling (2026-09-20): the never-used count rides inside
|
|
3357
|
+
Off-target; the separate face element stays hidden (titles on hover) */
|
|
3358
|
+
const dEl=el('rec-div');
|
|
3359
|
+
if(dEl){ dEl.hidden=true; }
|
|
3360
|
+
}
|
|
3361
|
+
|
|
3229
3362
|
let MODEL_LABEL='';
|
|
3230
3363
|
/* #409 fix round 5 — owner ruling 2026-09-14 (verbatim): "I do NOT want to
|
|
3231
3364
|
know what it is compatible with, I want to know the fucking model." The
|
package/dist/calibration.d.ts
CHANGED
|
@@ -105,6 +105,39 @@ export declare const RECALL_USES_NORMAL_MAX = 0.25;
|
|
|
105
105
|
* PROVISIONAL (owner anchor 2026-09-13, #426) — chosen so Overfetching
|
|
106
106
|
* keeps a visible span, not a measured bound. */
|
|
107
107
|
export declare const RECALL_USES_AXIS_MAX = 0.3;
|
|
108
|
+
/**
|
|
109
|
+
* Retention horizon for the recall_pushes/recall_events sidecar tables AND the
|
|
110
|
+
* longest window the Memory Precision card shows — ONE constant feeds both
|
|
111
|
+
* (the CAPTURE_HEALTH_WINDOW_DAYS single-constant law: the card can never
|
|
112
|
+
* claim a window the store no longer has rows for). 90 = the longest #452
|
|
113
|
+
* range option that the retention can honestly serve; 180d and all clamp to
|
|
114
|
+
* it server-side and the payload echoes the effective window_days.
|
|
115
|
+
*/
|
|
116
|
+
export declare const MEMORY_PRECISION_WINDOW_DAYS = 90;
|
|
117
|
+
/**
|
|
118
|
+
* Cosine at/above which a pushed line reads "redundant" (restating the
|
|
119
|
+
* session's standing context — the top lessons + identity every session-start
|
|
120
|
+
* hook injects). Direction-only display guidance, never a gate. 0.80 mirrors
|
|
121
|
+
* SUPERSESSION_MIN_SIMILARITY: at/above it a pair reads as the same
|
|
122
|
+
* statement, below it as topical overlap — a reasonable first anchor until
|
|
123
|
+
* the judged-calibration follow-up measures the real distribution (the
|
|
124
|
+
* #426 provisional-anchor posture).
|
|
125
|
+
*/
|
|
126
|
+
export declare const MEMORY_PRECISION_REDUNDANT_ABOVE = 0.8;
|
|
127
|
+
/**
|
|
128
|
+
* Window showings a live memory needs (with zero window fetches) to count as
|
|
129
|
+
* DIVERGING — the index keeps pushing it, nothing ever reads it. 5 is the
|
|
130
|
+
* spec's anchor (#476): enough showings that the silence is a pattern, not
|
|
131
|
+
* one prompt's turn-suppression.
|
|
132
|
+
*/
|
|
133
|
+
export declare const MEMORY_PRECISION_DIVERGENCE_MIN_SHOWN = 5;
|
|
134
|
+
/**
|
|
135
|
+
* Cap on the prompt excerpt persisted per recall_pushes row (Option A,
|
|
136
|
+
* owner-blessed 2026-09-19: the first-ever server-side persistence of raw
|
|
137
|
+
* prompt text, bounded to 256 chars and pruned at the retention horizon —
|
|
138
|
+
* the same trust boundary as /distill's denoised conversation text).
|
|
139
|
+
*/
|
|
140
|
+
export declare const MEMORY_PRECISION_PROMPT_EXCERPT_CHARS = 256;
|
|
108
141
|
/** Semantic-similarity share of the composite score. 0.50 (raised from 0.40
|
|
109
142
|
* in the 0.15.2 rebalance, #191 Phase B): on the production corpus effective
|
|
110
143
|
* strength (0.30) outweighed what similarity could recover — hardened old
|
|
@@ -115,23 +148,58 @@ export declare const SCORE_SIMILARITY_WEIGHT = 0.5;
|
|
|
115
148
|
export declare const SCORE_STRENGTH_WEIGHT = 0.2;
|
|
116
149
|
/** Graph-centrality share of the composite score (was 0.20; see above). */
|
|
117
150
|
export declare const SCORE_CONNECTIONS_WEIGHT = 0.15;
|
|
118
|
-
/**
|
|
151
|
+
/**
|
|
152
|
+
* Log-saturation degree K for the connections term (#449 PR E, items 1+3):
|
|
153
|
+
* the credit is min(1, log1p(k) / log1p(K)) × SCORE_CONNECTIONS_WEIGHT on
|
|
154
|
+
* the ABSOLUTE undirected-degree scale k — full at k = K, exactly +0 at
|
|
155
|
+
* k = 0 (unlinked rows score bit-identically to the linear term they
|
|
156
|
+
* replace). Provenance: p99 of the REAL undirected degree distribution
|
|
157
|
+
* (read-only audit 2026-09-17 of the canonical wave snapshot, 18,798
|
|
158
|
+
* memories / 14,600 linked: p50 = 4, p90 = 8, p95 = 9, p99 = 15, p99.9 =
|
|
159
|
+
* 28.4, max = 40; 135 memories ≥ 16 links = 0.92% of linked) — so the top
|
|
160
|
+
* ~1% of hubs tie at full credit and everything below differentiates
|
|
161
|
+
* modestly. Shape grounded in the #449 research base: ACT-R fan saturation
|
|
162
|
+
* (Anderson & Reder 1999 — activation falls with the LOG of fan), SAM's
|
|
163
|
+
* saturating returns, cue overload (Watkins & Watkins 1975). Replaces the
|
|
164
|
+
* candidate-set-relative normalization #449 deleted (k / the per-query max
|
|
165
|
+
* degree) — a row's score no longer depends on which other rows happened
|
|
166
|
+
* to match. Alternatives K = 8 (p90 — collapses all p90+ rows to
|
|
167
|
+
* full credit) and K = 32 (≈p99.9 — leaves the p99 hub at 0.12 of the
|
|
168
|
+
* term) were tabled in the #449 spec. RELEASE-MANAGED per this module's
|
|
169
|
+
* evolution contract — overridable only through the configureScoring seam.
|
|
170
|
+
*/
|
|
171
|
+
export declare const CONNECTIONS_SATURATION_DEGREE = 16;
|
|
172
|
+
/** Time-curve share of the composite score — the merged curve's blend weight
|
|
173
|
+
* AND slow-region amplitude (was 0.10; see above). The four blend weights
|
|
174
|
+
* still sum to 1.0; the head amplitude below is a documented overshoot, NOT
|
|
175
|
+
* a fifth blend weight (#430). Zero (via the seam) disables the whole term. */
|
|
119
176
|
export declare const SCORE_RECENCY_WEIGHT = 0.15;
|
|
120
|
-
/**
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
177
|
+
/** Hourly decay of the merged curve's slow region (#430) — promoted from the
|
|
178
|
+
* inline literal computeScore carried; half-life ≈ 57.7 days. At and beyond
|
|
179
|
+
* RECENCY_HEAD_DAYS the curve is bit-identical to the pre-#430 slow term
|
|
180
|
+
* (SCORE_RECENCY_WEIGHT × RECENCY_HOURLY_DECAY^hours). */
|
|
181
|
+
export declare const RECENCY_HOURLY_DECAY = 0.9995;
|
|
182
|
+
/** Merged time-curve head amplitude at age 0 (#430) — the pre-#430 slow
|
|
183
|
+
* weight 0.15 + fresh bonus 0.15: the freshness job is now the early steep
|
|
184
|
+
* part of ONE curve. The head joins value-continuously onto the slow region
|
|
185
|
+
* at RECENCY_HEAD_DAYS; its rate is DERIVED from that continuity, never a
|
|
186
|
+
* free constant. */
|
|
187
|
+
export declare const RECENCY_HEAD_WEIGHT = 0.3;
|
|
188
|
+
/** Join age in days of the merged time curve (#430) — the head window edge,
|
|
189
|
+
* carried over from the pre-#430 freshness window. Nightly capture means
|
|
190
|
+
* 1 day is the floor of "fresh" (#191 Phase B). */
|
|
191
|
+
export declare const RECENCY_HEAD_DAYS = 7;
|
|
126
192
|
/** Score multiplier for a memory a later decision superseded (0.15.2; the
|
|
127
193
|
* belief walk (#393 D) is the primary mechanism — this is the safety net
|
|
128
194
|
* for rows the walk does not reach). */
|
|
129
195
|
export declare const SUPERSEDED_DEMOTION = 0.5;
|
|
130
|
-
/** #
|
|
131
|
-
*
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
196
|
+
/** #430 merged scope affinity — ONE term replacing #203's two boosts (the
|
|
197
|
+
* project-affinity and domain-affinity constants) at their shared value.
|
|
198
|
+
* Boost = max(project-match indicator (1 on exact match), max overlapping
|
|
199
|
+
* domain-tag weight) × this weight: the strongest single scope signal counts
|
|
200
|
+
* once, never stacked. ADDITIVE, zero-boost neutral, never a penalty — an
|
|
201
|
+
* absent scope adds exactly 0; a foreign memory ranks equal, not lower. */
|
|
202
|
+
export declare const SCOPE_AFFINITY_WEIGHT = 0.15;
|
|
135
203
|
/** #205 RRF k parameter (1/(k+rank+1)) — matches the pre-#205 hardcoded 60
|
|
136
204
|
* so the no-config path was byte-identical to 0.15.3. */
|
|
137
205
|
export declare const RRF_K = 60;
|
|
@@ -188,6 +256,18 @@ export declare const BM25_WEIGHT_DOMAIN = 2;
|
|
|
188
256
|
* base-1.0 rows decay again.
|
|
189
257
|
*/
|
|
190
258
|
export declare const IMPORTANCE_CEILING = 0.95;
|
|
259
|
+
/**
|
|
260
|
+
* How many days a memory stays in the nightly importance-settle pool after
|
|
261
|
+
* ingest (#478): a row's importance re-settles nightly while young — keyed
|
|
262
|
+
* on PER-ROW age (ingested_at), never the global lastConsolidated
|
|
263
|
+
* watermark, which sticks whenever a run defers and used to drag a growing
|
|
264
|
+
* cohort back through re-scoring (each re-settle overwrites base_strength,
|
|
265
|
+
* erasing promotion gains). Rows leave the pool after the window; promoted
|
|
266
|
+
* or enriched rows leave earlier via the paid-gain guard. Release-managed
|
|
267
|
+
* (#408 discipline): moving it is a release decision with soak evidence,
|
|
268
|
+
* not a config knob.
|
|
269
|
+
*/
|
|
270
|
+
export declare const IMPORTANCE_SETTLE_WINDOW_DAYS = 3;
|
|
191
271
|
/** Deterministic merge ceiling of the unified resolution pass (#392): pairs
|
|
192
272
|
* at/above this cosine merge LLM-free; [CORRECTION_MIN_SIMILARITY, this)
|
|
193
273
|
* get the one verdict call. 0.92 — measured on the #191 mechanical audit
|