@gamaze/hicortex 0.22.1 → 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 +201 -74
- package/dist/calibration.d.ts +45 -0
- package/dist/calibration.js +52 -2
- package/dist/classify-domains.js +6 -1
- package/dist/consolidate.js +73 -14
- package/dist/dashboard.d.ts +11 -0
- package/dist/dashboard.js +9 -0
- package/dist/db.js +74 -0
- package/dist/mcp-server.js +35 -8
- 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/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 -->
|
|
@@ -1488,8 +1517,11 @@ const DEPTH_BANDS = { truth:[.9,1.05], belief:[1.05,1.3], forming:[1.3,1.55], fa
|
|
|
1488
1517
|
post-backfill store still shows a visible gradient and the inflated
|
|
1489
1518
|
pre-#425 store shows no monsters. Robust by construction: the mapping is
|
|
1490
1519
|
absolute (no min/max over the live distribution), so it cannot explode on
|
|
1491
|
-
a skewed store. Pure functions — the ratio is behaviorally tested.
|
|
1492
|
-
|
|
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; }
|
|
1493
1525
|
function depthSizeDivisor(dz){ return Math.pow(Math.max(.14,dz),0.35); }
|
|
1494
1526
|
|
|
1495
1527
|
/* ---------- live-data state ---------- */
|
|
@@ -1506,7 +1538,7 @@ let TOTAL=0, removedNow=0;
|
|
|
1506
1538
|
clock (owner ruling 2026-09-13; only the boot reveal counts up) */
|
|
1507
1539
|
|
|
1508
1540
|
/* =====================================================================
|
|
1509
|
-
WORLD — domains, memories
|
|
1541
|
+
WORLD — domains, memories, the dateline window (the visible set), real
|
|
1510
1542
|
links, the replay ledger. All positions derive from id hashes → stable
|
|
1511
1543
|
across reloads and across the refreshes after Update/Remove.
|
|
1512
1544
|
===================================================================== */
|
|
@@ -1515,8 +1547,14 @@ const PORT = [ [.50,.20,.15],[.28,.38,.12],[.74,.40,.12],[.50,.62,.13],[.25,.68,
|
|
|
1515
1547
|
let DOMAINS = []; // {name,count,land,port,cx,cy,cr}
|
|
1516
1548
|
const mems = new Map(); // id -> memory object (live + replay ghosts)
|
|
1517
1549
|
const links = []; // real link edges, engine-decorated
|
|
1518
|
-
const bubbles = []; // the ~120-mem interactive importance sample
|
|
1519
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;
|
|
1520
1558
|
let byAgentCounts = {}; // source_agent -> count
|
|
1521
1559
|
let CONTEXTS = []; // [{id,name,machine,count}] — #421 machine × harness grouping
|
|
1522
1560
|
let adj = new Map(); // id -> [neighbor ids] (real links)
|
|
@@ -1525,6 +1563,13 @@ let learnedL = [], mergedL = [], enrichedL = [];
|
|
|
1525
1563
|
let NIGHTS = []; // the events payload's night list
|
|
1526
1564
|
let WINDOW = 1, NOW_T = .999, REPLAY_OK = false;
|
|
1527
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
|
+
|
|
1528
1573
|
function domIndex(domain){ const i = DOMAINS.findIndex(d=>d.name===domain); return i<0?0:i; }
|
|
1529
1574
|
function titleOf(id){ const m=mems.get(id); return m?m.title:'(absorbed)'; }
|
|
1530
1575
|
|
|
@@ -1589,6 +1634,10 @@ function buildWorld(){
|
|
|
1589
1634
|
if(!m.ghost && !keep.has(id)) mems.delete(id);
|
|
1590
1635
|
}
|
|
1591
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
|
+
|
|
1592
1641
|
// replay metadata from the events ledger: in-window births + merge-outs
|
|
1593
1642
|
// (absorbed losers get ghost entries so their merge animation has a
|
|
1594
1643
|
// position and their birth a bloom — they are not part of the live field).
|
|
@@ -1657,34 +1706,12 @@ function buildWorld(){
|
|
|
1657
1706
|
}
|
|
1658
1707
|
}
|
|
1659
1708
|
|
|
1660
|
-
//
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
//
|
|
1665
|
-
|
|
1666
|
-
// (largest-remainder to the fixed total, minimum 1 each), each quota filled
|
|
1667
|
-
// by that stage's OWN strength→access ranking with an id-ASC tie-break —
|
|
1668
|
-
// fully deterministic, no Math.random. The old global top-120-by-strength
|
|
1669
|
-
// sample was 100% truth BY CONSTRUCTION (truth IS the top strength band),
|
|
1670
|
-
// so every touchable dot read green and the 1–2px crowd was visually
|
|
1671
|
-
// negligible; on an even store this yields ~30/30/30/30.
|
|
1672
|
-
bubbles.length = 0;
|
|
1673
|
-
{
|
|
1674
|
-
const BUBBLE_N=120;
|
|
1675
|
-
const stageArrs=STAGE_KEYS.map(k=>crowdByStage[k].filter(m=>!m.ghost)
|
|
1676
|
-
.sort((a,b)=> b.strength-a.strength || b.access-a.access || (a.id<b.id?-1:a.id>b.id?1:0)));
|
|
1677
|
-
const liveCount=stageArrs.reduce((n,a)=>n+a.length,0);
|
|
1678
|
-
if(liveCount>0){
|
|
1679
|
-
const exact=stageArrs.map(a=>a.length/liveCount*BUBBLE_N);
|
|
1680
|
-
const quota=exact.map(Math.floor);
|
|
1681
|
-
for(let i=0;i<quota.length;i++) if(quota[i]===0&&stageArrs[i].length>0) quota[i]=1;
|
|
1682
|
-
let left=BUBBLE_N-quota.reduce((n,q)=>n+q,0);
|
|
1683
|
-
const order=exact.map((_,i)=>i).sort((a,b)=>(exact[b]%1)-(exact[a]%1)); // remainder DESC, stage order tie
|
|
1684
|
-
for(let oi=0; left>0; oi++, left--) quota[order[oi%order.length]]++;
|
|
1685
|
-
stageArrs.forEach((a,i)=>{ bubbles.push(...a.slice(0,Math.min(quota[i],a.length))); });
|
|
1686
|
-
}
|
|
1687
|
-
}
|
|
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);
|
|
1688
1715
|
|
|
1689
1716
|
// contexts (source_agent values) with their machine stamps (#421 machine ×
|
|
1690
1717
|
// harness): the rail + capture card group on (machine ?? legacy) × harness.
|
|
@@ -1746,6 +1773,31 @@ function aliveAt(b,t){
|
|
|
1746
1773
|
return true;
|
|
1747
1774
|
}
|
|
1748
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
|
+
}
|
|
1749
1801
|
|
|
1750
1802
|
/* =====================================================================
|
|
1751
1803
|
THEME — one engine, two palettes. Dark (the brand night: glow) is the
|
|
@@ -1903,22 +1955,16 @@ function sprite(stage, r){
|
|
|
1903
1955
|
const st = PAL.stages[stage] || PAL.stages.forming;
|
|
1904
1956
|
const rgb = st.rgb;
|
|
1905
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. */
|
|
1906
1961
|
const S = Math.ceil(rad*PAL.sprK), c2 = document.createElement('canvas');
|
|
1907
1962
|
c2.width=S; c2.height=S;
|
|
1908
1963
|
const g = c2.getContext('2d'), cxp=S/2;
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
g.fillStyle=gr; g.fillRect(0,0,S,S);
|
|
1914
|
-
gr = g.createRadialGradient(cxp-rad*.28,cxp-rad*.32,rad*.1, cxp,cxp,rad);
|
|
1915
|
-
gr.addColorStop(0,'rgba(255,255,255,'+(.5*st.alpha)+')');
|
|
1916
|
-
gr.addColorStop(.35, rgba(rgb,.55*st.alpha));
|
|
1917
|
-
gr.addColorStop(.82, rgba(rgb,.22*st.alpha));
|
|
1918
|
-
gr.addColorStop(1, rgba(rgb,.04));
|
|
1919
|
-
g.fillStyle=gr; g.beginPath(); g.arc(cxp,cxp,rad,0,7); g.fill();
|
|
1920
|
-
g.strokeStyle=rgba(rgb,.34*st.alpha); g.lineWidth=1;
|
|
1921
|
-
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();
|
|
1922
1968
|
/* #422 round 2: fading's DISTINCT outer ring — the rim stage's fill runs
|
|
1923
1969
|
at low alpha by design; without its own edge treatment the dots were
|
|
1924
1970
|
illegible against the night ground */
|
|
@@ -2001,7 +2047,7 @@ function buildPaths(){
|
|
|
2001
2047
|
}
|
|
2002
2048
|
}
|
|
2003
2049
|
function pathAlive(p,t){
|
|
2004
|
-
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; }
|
|
2005
2051
|
return t>=p.born;
|
|
2006
2052
|
}
|
|
2007
2053
|
function spawnSignal(showcase){
|
|
@@ -2060,8 +2106,10 @@ function advanceSignals(now, dt){
|
|
|
2060
2106
|
}
|
|
2061
2107
|
|
|
2062
2108
|
/* =====================================================================
|
|
2063
|
-
THE FRAME — theme-aware;
|
|
2064
|
-
|
|
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.
|
|
2065
2113
|
===================================================================== */
|
|
2066
2114
|
let labelRects=[];
|
|
2067
2115
|
/* emergence queue (#422 live review): a night's births/links become VISIBLE
|
|
@@ -2105,6 +2153,7 @@ function processEmergence(t){
|
|
|
2105
2153
|
}
|
|
2106
2154
|
function draw(now, dt){
|
|
2107
2155
|
const t=T;
|
|
2156
|
+
refreshWindow(t); // #474: the visible set = latest-N by dateline at this T (bubbles, winSet, winCount)
|
|
2108
2157
|
const dark = PAL.name==='dark';
|
|
2109
2158
|
const ADD = dark ? 'lighter' : 'source-over';
|
|
2110
2159
|
ctx.clearRect(0,0,view.w,view.h);
|
|
@@ -2170,6 +2219,12 @@ function draw(now, dt){
|
|
|
2170
2219
|
}
|
|
2171
2220
|
ctx.globalAlpha=1;
|
|
2172
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
|
+
|
|
2173
2228
|
/* THE CROWD — every memory in the store as maturity-colored micro-stars
|
|
2174
2229
|
behind the touchable sample (no sampling: the dot count IS the store).
|
|
2175
2230
|
One fillStyle per stage pass. The emergence queue is resolved FIRST
|
|
@@ -2187,7 +2242,7 @@ function draw(now, dt){
|
|
|
2187
2242
|
if(fog<.15) continue;
|
|
2188
2243
|
const [sx,sy]=proj3(m.nx||.5,m.ny||.5,dz);
|
|
2189
2244
|
if(sx<-2||sy<-2||sx>view.w+2||sy>view.h+2) continue;
|
|
2190
|
-
ctx.globalAlpha=fog*.5;
|
|
2245
|
+
ctx.globalAlpha=fog*.5*(focusDom!=null&&m.dom!==focusDom?.15:1);
|
|
2191
2246
|
const px=Math.max(1,Math.round((rand01(m.id,9)<.85?1:1.8)/dz*1.4));
|
|
2192
2247
|
ctx.fillRect(sx,sy,px,px);
|
|
2193
2248
|
}
|
|
@@ -2241,6 +2296,7 @@ function draw(now, dt){
|
|
|
2241
2296
|
if(L.rk>=lodK) continue; // zoom LOD (lines only)
|
|
2242
2297
|
const a=mems.get(L.a), b=mems.get(L.b);
|
|
2243
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 */
|
|
2244
2300
|
if(a._emerged===false||b._emerged===false) continue; // thread waits for both endpoints
|
|
2245
2301
|
const [ax,ay]=bpos(a,now,t), [bx,by]=bpos(b,now,t);
|
|
2246
2302
|
const ctrl=segCtrlN(ax,ay,bx,by,(L.use>18?1:-1));
|
|
@@ -2255,6 +2311,9 @@ function draw(now, dt){
|
|
|
2255
2311
|
const prog = L.forming ? clamp((t-(L._emergeT!==undefined?L._emergeT:L.born))/1.4,0,1) : 1;
|
|
2256
2312
|
const drawP=Math.min(prog,linkBoot);
|
|
2257
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;
|
|
2258
2317
|
const len=Math.hypot(x2-x1,y2-y1)*1.15;
|
|
2259
2318
|
const superFam = L.rel==='superseded_by'||L.rel==='corrected_by';
|
|
2260
2319
|
/* fix-round-3 weights: settled alphas roughly halved (both themes) so the
|
|
@@ -2262,7 +2321,7 @@ function draw(now, dt){
|
|
|
2262
2321
|
const bright=(a.stage==='truth'||b.stage==='truth') ? (dark?.07:.11) : (dark?.035:.06);
|
|
2263
2322
|
const baseW=.34+useF*.55+heat*.5;
|
|
2264
2323
|
/* the SETTLED stroke is always the base */
|
|
2265
|
-
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);
|
|
2266
2325
|
ctx.lineWidth=baseW;
|
|
2267
2326
|
ctx.setLineDash(superFam?[4,4]:[len*drawP,1e5]);
|
|
2268
2327
|
ctx.beginPath(); ctx.moveTo(x1,y1); ctx.quadraticCurveTo(cx1,cy1,x2,y2); ctx.stroke();
|
|
@@ -2271,7 +2330,7 @@ function draw(now, dt){
|
|
|
2271
2330
|
in the same proportion as the settled stroke) */
|
|
2272
2331
|
const settle=1-prog;
|
|
2273
2332
|
const baseA=(dark? .07 : .09)+((dark?.15:.17)-(dark?.07:.09))*drawP;
|
|
2274
|
-
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);
|
|
2275
2334
|
ctx.lineWidth=baseW+(.18+drawP*.3)*settle;
|
|
2276
2335
|
ctx.setLineDash(superFam?[4,4]:[len*drawP,1e5]);
|
|
2277
2336
|
ctx.beginPath(); ctx.moveTo(x1,y1); ctx.quadraticCurveTo(cx1,cy1,x2,y2); ctx.stroke();
|
|
@@ -2346,8 +2405,9 @@ function draw(now, dt){
|
|
|
2346
2405
|
dark-blue-on-near-black at ~4px read invisible to a vision model);
|
|
2347
2406
|
the projection factor is known here, and far-stage bubbles (rim depth
|
|
2348
2407
|
/ small viewports) were collapsing to ~1-2px. Every stage stays a
|
|
2349
|
-
legible glimmer; ordering untouched.
|
|
2350
|
-
|
|
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);
|
|
2351
2411
|
let remA=1;
|
|
2352
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; } }
|
|
2353
2413
|
const ex=b._ex||0;
|
|
@@ -2447,8 +2507,11 @@ function draw(now, dt){
|
|
|
2447
2507
|
ctx.font=(9.5*k).toFixed(1)+'px '+FF;
|
|
2448
2508
|
try{ ctx.letterSpacing=(1*k).toFixed(1)+'px'; }catch(e){}
|
|
2449
2509
|
ctx.fillStyle= dark? 'rgba(90,90,90,'+(.85*dimming*lp)+')' : hexA(PAL.labelCount,dimming*lp);
|
|
2450
|
-
|
|
2451
|
-
|
|
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;
|
|
2452
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)+')');
|
|
2453
2516
|
ctx.lineWidth=1;
|
|
2454
2517
|
const bx=sx-9*k, by=sy-11*k, bxx=bx+bw+9*k, byy=by+15*k, tk=4*k;
|
|
@@ -2613,18 +2676,18 @@ function autoTick(now){
|
|
|
2613
2676
|
if(T>=NOW_T-.001){
|
|
2614
2677
|
/* a beat at "now": re-kick to the range start ONLY before the first
|
|
2615
2678
|
full playback; after it, REST here — plays once, never loops (#452) */
|
|
2616
|
-
if(played){ autoPlay=false; autoNextAt=now+
|
|
2617
|
-
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;
|
|
2618
2681
|
}
|
|
2619
2682
|
while(autoEvIdx<EVENTS.length && EVENTS[autoEvIdx].t<=T+.0001) autoEvIdx++;
|
|
2620
2683
|
if(autoEvIdx>=EVENTS.length){
|
|
2621
2684
|
/* ledger exhausted: arrive at today and complete the playback (the
|
|
2622
2685
|
flags go BEFORE the seek so onTChanged's control swap sees them) */
|
|
2623
|
-
autoNextAt=now+
|
|
2686
|
+
autoNextAt=now+REPLAY_REST_MS; played=true; autoPlay=false; seek(WINDOW); return;
|
|
2624
2687
|
}
|
|
2625
2688
|
const ev=EVENTS[autoEvIdx++];
|
|
2626
|
-
if(ev.id && signals.length<8){ heraldTo(ev.id); pendingApply={t:ev.t+.001, at:now+
|
|
2627
|
-
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; }
|
|
2628
2691
|
}
|
|
2629
2692
|
track.addEventListener('pointerdown',e=>{ if(!REPLAY_OK) return; scrubbing=true; manualTake(); track.setPointerCapture(e.pointerId); seek(trackFrac(e)*WINDOW); });
|
|
2630
2693
|
track.addEventListener('pointermove',e=>{ if(scrubbing) seek(trackFrac(e)*WINDOW); });
|
|
@@ -2841,7 +2904,8 @@ cv.addEventListener('pointermove',e=>{
|
|
|
2841
2904
|
tip.style.display='block';
|
|
2842
2905
|
tip.style.left=Math.min(e.clientX+14,window.innerWidth-300)+'px';
|
|
2843
2906
|
tip.style.top=(e.clientY+16)+'px';
|
|
2844
|
-
|
|
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>';
|
|
2845
2909
|
}else tip.style.display='none';
|
|
2846
2910
|
dirty=true;
|
|
2847
2911
|
});
|
|
@@ -3180,7 +3244,14 @@ function recallGradAt(frac,z,theme){
|
|
|
3180
3244
|
}
|
|
3181
3245
|
let lastRecUses=null; /* setTheme's re-render carries the last value */
|
|
3182
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;
|
|
3183
3253
|
lastRecUses=ups;
|
|
3254
|
+
renderRecL1(mp);
|
|
3184
3255
|
const z=F&&F.thresholds?F.thresholds.recall_uses:null;
|
|
3185
3256
|
const axis=z&&typeof z.axis_max==='number'&&z.axis_max>0?z.axis_max:null;
|
|
3186
3257
|
const row=el('rec-bandrow'), band=el('rec-band'), dot=el('rec-dot'), word=el('rec-zone');
|
|
@@ -3204,7 +3275,7 @@ function renderRecBand(ups){
|
|
|
3204
3275
|
if(zk){
|
|
3205
3276
|
dot.hidden=false;
|
|
3206
3277
|
dot.style.left=pct(ups)+'%';
|
|
3207
|
-
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';
|
|
3208
3279
|
word.textContent=RECALL_ZONE_WORD[zk];
|
|
3209
3280
|
word.className='n rec-word';
|
|
3210
3281
|
/* the big word's color = the gradient sampled AT the marker — the word
|
|
@@ -3232,6 +3303,62 @@ function renderRecBand(ups){
|
|
|
3232
3303
|
}
|
|
3233
3304
|
}
|
|
3234
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
|
+
|
|
3235
3362
|
let MODEL_LABEL='';
|
|
3236
3363
|
/* #409 fix round 5 — owner ruling 2026-09-14 (verbatim): "I do NOT want to
|
|
3237
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
|
|
@@ -223,6 +256,18 @@ export declare const BM25_WEIGHT_DOMAIN = 2;
|
|
|
223
256
|
* base-1.0 rows decay again.
|
|
224
257
|
*/
|
|
225
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;
|
|
226
271
|
/** Deterministic merge ceiling of the unified resolution pass (#392): pairs
|
|
227
272
|
* at/above this cosine merge LLM-free; [CORRECTION_MIN_SIMILARITY, this)
|
|
228
273
|
* get the one verdict call. 0.92 — measured on the #191 mechanical audit
|
package/dist/calibration.js
CHANGED
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
* the removal is never silent.
|
|
25
25
|
*/
|
|
26
26
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
27
|
-
exports.
|
|
28
|
-
exports.DIAGNOSTIC_ENV_TIER = void 0;
|
|
27
|
+
exports.STAGE_TRUTH_STRENGTH = exports.STAGE_BELIEF_STRENGTH = exports.STAGE_FADING_STRENGTH = exports.STAGE_FADING_DAYS = exports.WEAK_PRIMARY_FLOOR = exports.CORRECTION_REWRITE_MIN_CONFIDENCE = exports.CORRECTION_MIN_SIMILARITY = exports.SUPERSESSION_MIN_SIMILARITY = exports.DEDUP_AUTO_MERGE_THRESHOLD = exports.IMPORTANCE_SETTLE_WINDOW_DAYS = exports.IMPORTANCE_CEILING = exports.BM25_WEIGHT_DOMAIN = exports.BM25_WEIGHT_PROJECT = exports.BM25_WEIGHT_BODY = exports.BOTH_CHANNEL_BOOST = exports.RRF_VECTOR_WEIGHT = exports.RRF_FTS_WEIGHT = exports.RRF_COMPOSITE_WEIGHT = exports.RRF_K = exports.SCOPE_AFFINITY_WEIGHT = exports.SUPERSEDED_DEMOTION = exports.RECENCY_HEAD_DAYS = exports.RECENCY_HEAD_WEIGHT = exports.RECENCY_HOURLY_DECAY = exports.SCORE_RECENCY_WEIGHT = exports.CONNECTIONS_SATURATION_DEGREE = exports.SCORE_CONNECTIONS_WEIGHT = exports.SCORE_STRENGTH_WEIGHT = exports.SCORE_SIMILARITY_WEIGHT = exports.MEMORY_PRECISION_PROMPT_EXCERPT_CHARS = exports.MEMORY_PRECISION_DIVERGENCE_MIN_SHOWN = exports.MEMORY_PRECISION_REDUNDANT_ABOVE = exports.MEMORY_PRECISION_WINDOW_DAYS = exports.RECALL_USES_AXIS_MAX = exports.RECALL_USES_NORMAL_MAX = exports.RECALL_USES_LOW_MAX = exports.RECALL_RESHOW_TURNS = exports.NOVELTY_FLOOR_SLOTS = exports.RECALL_TITLE_CHARS = exports.RECALL_MIN_PROMPT_CHARS = exports.RECALL_MAX_ITEMS = exports.RECALL_MIN_SIMILARITY = exports.SESSION_INTENT_WEIGHT = exports.COLD_EXPOSURE_SLOTS = exports.RECENT_WINDOW_DAYS = exports.RECENT_LIMIT = exports.SEARCH_LIMIT = exports.PROMOTION_STRENGTH_FLOOR = exports.PROMOTION_RATE = exports.DECAY_HALF_LIFE_DAYS = void 0;
|
|
28
|
+
exports.DIAGNOSTIC_ENV_TIER = exports.OLLAMA_FLUSH_WAIT_MS = exports.OLLAMA_FLUSH_EVERY = exports.NUM_CTX = exports.DEFAULT_FIRST_RUN_LOOKBACK_DAYS = exports.ENRICH_STRENGTH_DELTA = void 0;
|
|
29
29
|
exports.resolveNumCtx = resolveNumCtx;
|
|
30
30
|
exports.resolveOllamaFlushEvery = resolveOllamaFlushEvery;
|
|
31
31
|
exports.resolveOllamaFlushWaitMs = resolveOllamaFlushWaitMs;
|
|
@@ -127,6 +127,44 @@ exports.RECALL_USES_NORMAL_MAX = 0.25;
|
|
|
127
127
|
* PROVISIONAL (owner anchor 2026-09-13, #426) — chosen so Overfetching
|
|
128
128
|
* keeps a visible span, not a measured bound. */
|
|
129
129
|
exports.RECALL_USES_AXIS_MAX = 0.30;
|
|
130
|
+
// Memory-precision family (#476) — the console card's deterministic proxies.
|
|
131
|
+
// All four are release-managed per this module's evolution contract: no config
|
|
132
|
+
// keys, nothing hardcoded elsewhere. Values are stored THRESHOLD-FREE (raw
|
|
133
|
+
// cosines in recall_events); the thresholds below are applied at RENDER time
|
|
134
|
+
// only, so recalibrating them never rewrites history.
|
|
135
|
+
/**
|
|
136
|
+
* Retention horizon for the recall_pushes/recall_events sidecar tables AND the
|
|
137
|
+
* longest window the Memory Precision card shows — ONE constant feeds both
|
|
138
|
+
* (the CAPTURE_HEALTH_WINDOW_DAYS single-constant law: the card can never
|
|
139
|
+
* claim a window the store no longer has rows for). 90 = the longest #452
|
|
140
|
+
* range option that the retention can honestly serve; 180d and all clamp to
|
|
141
|
+
* it server-side and the payload echoes the effective window_days.
|
|
142
|
+
*/
|
|
143
|
+
exports.MEMORY_PRECISION_WINDOW_DAYS = 90;
|
|
144
|
+
/**
|
|
145
|
+
* Cosine at/above which a pushed line reads "redundant" (restating the
|
|
146
|
+
* session's standing context — the top lessons + identity every session-start
|
|
147
|
+
* hook injects). Direction-only display guidance, never a gate. 0.80 mirrors
|
|
148
|
+
* SUPERSESSION_MIN_SIMILARITY: at/above it a pair reads as the same
|
|
149
|
+
* statement, below it as topical overlap — a reasonable first anchor until
|
|
150
|
+
* the judged-calibration follow-up measures the real distribution (the
|
|
151
|
+
* #426 provisional-anchor posture).
|
|
152
|
+
*/
|
|
153
|
+
exports.MEMORY_PRECISION_REDUNDANT_ABOVE = 0.8;
|
|
154
|
+
/**
|
|
155
|
+
* Window showings a live memory needs (with zero window fetches) to count as
|
|
156
|
+
* DIVERGING — the index keeps pushing it, nothing ever reads it. 5 is the
|
|
157
|
+
* spec's anchor (#476): enough showings that the silence is a pattern, not
|
|
158
|
+
* one prompt's turn-suppression.
|
|
159
|
+
*/
|
|
160
|
+
exports.MEMORY_PRECISION_DIVERGENCE_MIN_SHOWN = 5;
|
|
161
|
+
/**
|
|
162
|
+
* Cap on the prompt excerpt persisted per recall_pushes row (Option A,
|
|
163
|
+
* owner-blessed 2026-09-19: the first-ever server-side persistence of raw
|
|
164
|
+
* prompt text, bounded to 256 chars and pruned at the retention horizon —
|
|
165
|
+
* the same trust boundary as /distill's denoised conversation text).
|
|
166
|
+
*/
|
|
167
|
+
exports.MEMORY_PRECISION_PROMPT_EXCERPT_CHARS = 256;
|
|
130
168
|
// ---------------------------------------------------------------------------
|
|
131
169
|
// Composite ranking weights (was: score*Weight, supersededDemotion,
|
|
132
170
|
// *AffinityWeight, rrf*; the pre-#430 freshness bonus constants merged into
|
|
@@ -260,6 +298,18 @@ exports.BM25_WEIGHT_DOMAIN = 2.0;
|
|
|
260
298
|
* base-1.0 rows decay again.
|
|
261
299
|
*/
|
|
262
300
|
exports.IMPORTANCE_CEILING = 0.95;
|
|
301
|
+
/**
|
|
302
|
+
* How many days a memory stays in the nightly importance-settle pool after
|
|
303
|
+
* ingest (#478): a row's importance re-settles nightly while young — keyed
|
|
304
|
+
* on PER-ROW age (ingested_at), never the global lastConsolidated
|
|
305
|
+
* watermark, which sticks whenever a run defers and used to drag a growing
|
|
306
|
+
* cohort back through re-scoring (each re-settle overwrites base_strength,
|
|
307
|
+
* erasing promotion gains). Rows leave the pool after the window; promoted
|
|
308
|
+
* or enriched rows leave earlier via the paid-gain guard. Release-managed
|
|
309
|
+
* (#408 discipline): moving it is a release decision with soak evidence,
|
|
310
|
+
* not a config knob.
|
|
311
|
+
*/
|
|
312
|
+
exports.IMPORTANCE_SETTLE_WINDOW_DAYS = 3;
|
|
263
313
|
/** Deterministic merge ceiling of the unified resolution pass (#392): pairs
|
|
264
314
|
* at/above this cosine merge LLM-free; [CORRECTION_MIN_SIMILARITY, this)
|
|
265
315
|
* get the one verdict call. 0.92 — measured on the #191 mechanical audit
|
package/dist/classify-domains.js
CHANGED
|
@@ -175,10 +175,15 @@ async function runClassifyDomains(options = {}) {
|
|
|
175
175
|
// everything from the final tag sets.
|
|
176
176
|
const { prototypes } = await (0, schema_prototypes_js_1.computeDomainPrototypes)(db, domains, getEmbedFn);
|
|
177
177
|
// Scope filter: default = NULL / not-in-set / no tags yet; --all = everything.
|
|
178
|
+
// #477: absorbed dedup losers are excluded from the default scope (dead
|
|
179
|
+
// evidence — the merge already cleared their tags and nulled domain);
|
|
180
|
+
// conjoined OUTSIDE the parenthesized OR group, same as the nightly
|
|
181
|
+
// stageContentDomains twin. --all stays a wholesale operator re-judge.
|
|
178
182
|
const placeholders = domains.map(() => "?").join(", ");
|
|
179
183
|
const scopeSql = all
|
|
180
184
|
? "rowid > ?"
|
|
181
|
-
: `rowid > ? AND (
|
|
185
|
+
: `rowid > ? AND COALESCE(status, '') != 'absorbed' ` +
|
|
186
|
+
`AND (domain IS NULL OR domain NOT IN (${placeholders}) ` +
|
|
182
187
|
`OR id NOT IN (SELECT DISTINCT memory_id FROM memory_tags))`;
|
|
183
188
|
const batchStmt = db.prepare(`SELECT rowid AS __rowid, id, content, project, domain FROM memories
|
|
184
189
|
WHERE ${scopeSql} ORDER BY rowid ASC LIMIT ?`);
|