@gamaze/hicortex 0.21.0 → 0.22.0
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 +274 -25
- package/dist/calibration.d.ts +30 -0
- package/dist/calibration.js +31 -1
- package/dist/capture-health.d.ts +42 -5
- package/dist/capture-health.js +57 -7
- package/dist/capture-pause.d.ts +7 -4
- package/dist/capture-pause.js +7 -4
- package/dist/consolidate.d.ts +19 -0
- package/dist/consolidate.js +116 -51
- package/dist/dashboard.d.ts +41 -16
- package/dist/dashboard.js +110 -41
- package/dist/db.js +16 -0
- package/dist/dedup.js +4 -1
- package/dist/eval/decay-eval.d.ts +2 -3
- package/dist/eval/decay-eval.js +6 -44
- package/dist/eval/ranking-eval.js +1 -1
- package/dist/eval/ranking-fixtures.d.ts +5 -5
- package/dist/eval/ranking-fixtures.js +7 -7
- package/dist/eval/run-eval.js +1 -1
- package/dist/graph.d.ts +1 -2
- package/dist/graph.js +3 -4
- package/dist/mcp-server.js +1 -1
- package/dist/nofit.d.ts +2 -1
- package/dist/nofit.js +2 -1
- package/dist/recall-index.d.ts +3 -2
- package/dist/recall-index.js +3 -2
- package/dist/retrieval.d.ts +9 -3
- package/dist/retrieval.js +21 -32
- package/dist/status.js +18 -0
- package/dist/storage.d.ts +2 -1
- package/dist/storage.js +6 -1
- package/dist/types.d.ts +25 -4
- package/package.json +1 -1
- package/server.json +4 -4
package/assets/dashboard.html
CHANGED
|
@@ -15,17 +15,22 @@
|
|
|
15
15
|
PORTED FROM mockups/409-r6-flight.html (the design of record — its banner
|
|
16
16
|
documents every behavior; the engine below is that page with the seeded
|
|
17
17
|
data layer replaced by fetches). Live-data substitutions:
|
|
18
|
-
/dashboard/data?range=
|
|
18
|
+
/dashboard/data?range=Rd — band numbers, snapshot series, digest
|
|
19
19
|
/dashboard/field — the whole field (memories + real links)
|
|
20
|
-
/dashboard/events?days=
|
|
20
|
+
/dashboard/events?days=R — the replay ledger (real nights)
|
|
21
21
|
/health + /health/detail — live dot (30 s poll) + model label
|
|
22
22
|
/account + /account/token — the account menu (harvested from 0.20.4)
|
|
23
23
|
/search /memory /update /delete /identity — the browser + agent rail
|
|
24
|
+
(R = the range selector's value: 30 by default, 7/90/180 opt-in — #452)
|
|
24
25
|
|
|
25
26
|
PHASE 2 (#422 — operator surfaces) LANDED:
|
|
26
27
|
- Capture health: real /distill accounting rows (posts · sessions · MB ·
|
|
27
28
|
held per machine × harness) via /dashboard/data capture_health; the
|
|
28
29
|
phase-1 counts-only rows remain as the degrade.
|
|
30
|
+
Fix round 7 (#409, owner ruling 2026-09-14 — "the normal 30 day as the
|
|
31
|
+
other cards"): the card's face is the ROLLING window (window_rows,
|
|
32
|
+
window_days), the newest night rides as a per-row secondary suffix;
|
|
33
|
+
retention == window (CAPTURE_HEALTH_WINDOW_DAYS).
|
|
29
34
|
- Activity bars: five segments (added + merged + the three graduation
|
|
30
35
|
deltas from snapshot stage_counts; two-segment rendering when buckets
|
|
31
36
|
are absent).
|
|
@@ -132,6 +137,30 @@
|
|
|
132
137
|
stays marked; the visible word failed to communicate). Vocabulary
|
|
133
138
|
amendment: Low / HEALTHY / Overfetching. Marker + trend stay.
|
|
134
139
|
|
|
140
|
+
REPLAY + RANGE (#452, owner directives 2026-09-16):
|
|
141
|
+
- 30-DAY DEFAULT FOR ALL VIEWS: the replay ledger, the band and the
|
|
142
|
+
snapshot series all default to 30 days (server EVENTS_DEFAULT_DAYS
|
|
143
|
+
90 → 30; the client's every fetch is selector-driven). Longer
|
|
144
|
+
ranges are OPT-IN via a compact 7 / 30 / 90 / 180 segmented control
|
|
145
|
+
in the replay foot — explicit click only, never auto-loaded
|
|
146
|
+
(SUPERSEDES the 2026-09-12 no-dropdowns ruling). No persistence:
|
|
147
|
+
every load starts at 30 (loads fast).
|
|
148
|
+
- PLAY ONCE, THEN REST: the replay auto-starts as before (~3.6 s after
|
|
149
|
+
boot), walks the ledger ONCE to today, and STOPS there — no loop
|
|
150
|
+
(SUPERSEDES the 2026-09-13 auto-loop/no-buttons ruling). Controls in
|
|
151
|
+
the replay foot, styled like "return to now": pause/resume (holds
|
|
152
|
+
position mid-cruise; hides once the playback completed — nothing is
|
|
153
|
+
playing) and "replay again" (appears once completed; restarts from
|
|
154
|
+
the range start). Drag/scrub behavior is UNCHANGED: a manual take
|
|
155
|
+
pauses the cruise and re-engages ~12 s after idle, continuing
|
|
156
|
+
toward today — where it now stops instead of looping.
|
|
157
|
+
- DATE LABEL ON THE SCRUBBER: the cursor dot carries a small mono
|
|
158
|
+
label above it (the night being viewed, "now" at the end).
|
|
159
|
+
- TRUTH-MANAGEMENT CAPTIONS: Superseded / Retracted / Rewritten ride
|
|
160
|
+
the events ledger alongside learned/enriched/merged (server-side
|
|
161
|
+
sources in dashboard.ts; superseded/retracted bloom in the fading
|
|
162
|
+
color — demoted — rewritten in the truth color).
|
|
163
|
+
|
|
135
164
|
REMAINING DEGRADATIONS (planned, per the #409 phase table — not gaps):
|
|
136
165
|
- Recall card: no raw shown/used counts (the per-memory adoption sums
|
|
137
166
|
are not in any payload yet).
|
|
@@ -561,11 +590,25 @@
|
|
|
561
590
|
pointer-events:none; transition:opacity 1.4s; z-index:5;
|
|
562
591
|
}
|
|
563
592
|
.hint em{ font-style:normal; color:var(--dim); }
|
|
564
|
-
/* replay — inside the brain panel; drag
|
|
593
|
+
/* replay — inside the brain panel; drag to scrub, or let the cruise walk
|
|
594
|
+
the ledger ONCE to today (#452: range pills + pause / replay again) */
|
|
565
595
|
.replay-foot{ border-top:1px solid var(--line); padding:7px 12px 8px; flex:none; background:color-mix(in srgb, var(--panel) 88%, transparent); }
|
|
566
596
|
#replay{ display:flex; align-items:center; gap:12px; }
|
|
567
597
|
#replay.off{ opacity:.45; pointer-events:none; }
|
|
598
|
+
/* the range selector stays LIVE even when the instrument is off — a wider
|
|
599
|
+
window can reveal ≥2 nights and revive the replay (#452) */
|
|
600
|
+
#replay.off #rp-range{ opacity:1; pointer-events:auto; }
|
|
568
601
|
#rp-label{ font-size:10px; color:var(--faint); text-transform:uppercase; letter-spacing:.14em; white-space:nowrap; flex:none; }
|
|
602
|
+
/* #452 range selector — the .idpill.seg idiom (mono pills, active = green) */
|
|
603
|
+
#rp-range{ display:inline-flex; gap:3px; flex:none; }
|
|
604
|
+
.rp-seg{
|
|
605
|
+
font-size:9px; font-family:var(--mono); letter-spacing:.05em; color:var(--faint);
|
|
606
|
+
border:1px solid var(--line2); border-radius:999px; padding:3px 8px; white-space:nowrap;
|
|
607
|
+
transition:color .15s, border-color .15s;
|
|
608
|
+
}
|
|
609
|
+
.rp-seg:hover{ color:var(--dim); }
|
|
610
|
+
.rp-seg[aria-pressed="true"]{ color:var(--green-mid); border-color:color-mix(in srgb, var(--green) 40%, transparent); }
|
|
611
|
+
html:not([data-theme="light"]) .rp-seg[aria-pressed="true"]{ box-shadow:0 0 10px rgba(61,255,122,.12); }
|
|
569
612
|
#rp-track{ flex:1; position:relative; height:26px; cursor:pointer; touch-action:none; min-width:60px; }
|
|
570
613
|
#rp-rail{ position:absolute; left:0; right:0; top:11px; height:3px; border-radius:2px; background:var(--tbar-bg); }
|
|
571
614
|
#rp-fill{ position:absolute; left:0; top:11px; height:3px; border-radius:2px; width:100%;
|
|
@@ -577,14 +620,23 @@
|
|
|
577
620
|
}
|
|
578
621
|
html:not([data-theme="light"]) #rp-cursor{ background:#0d1f14; box-shadow:0 0 12px rgba(61,255,122,.7); }
|
|
579
622
|
html[data-theme="light"] #rp-cursor{ box-shadow:0 1px 4px rgba(56,54,42,.3); }
|
|
623
|
+
/* #452: the night being viewed, floating above the scrub dot (the
|
|
624
|
+
#rp-dates span styling; overflow is visible — it may overlap the canvas
|
|
625
|
+
bottom edge like .hint does) */
|
|
626
|
+
#rp-date{
|
|
627
|
+
position:absolute; top:-13px; transform:translateX(-50%); white-space:nowrap;
|
|
628
|
+
font-size:9px; color:var(--faint); font-family:var(--mono); pointer-events:none; z-index:3;
|
|
629
|
+
display:none;
|
|
630
|
+
}
|
|
631
|
+
#rp-date.show{ display:block; }
|
|
580
632
|
.rp-dot{ position:absolute; top:9px; width:5px; height:5px; border-radius:50%; margin-left:-2.5px; background:var(--line2); }
|
|
581
633
|
.rp-dot.g{ background:var(--green-mid); }
|
|
582
634
|
.rp-dot.w{ background:var(--dim); }
|
|
583
635
|
#rp-dates{ position:absolute; left:0; right:0; top:21px; height:12px; }
|
|
584
636
|
#rp-dates span{ position:absolute; transform:translateX(-50%); font-size:9px; color:var(--faint); font-family:var(--mono); }
|
|
585
|
-
#rp-now{ display:none; font-size:10.5px; color:var(--green-mid); border:1px solid color-mix(in srgb, var(--green) 40%, transparent); border-radius:999px; padding:5px 11px; white-space:nowrap; }
|
|
586
|
-
#rp-now.show{ display:inline-block; }
|
|
587
|
-
html:not([data-theme="light"]) #rp-now{ box-shadow:0 0 12px rgba(61,255,122,.15); }
|
|
637
|
+
#rp-now,#rp-pause,#rp-again{ display:none; font-size:10.5px; color:var(--green-mid); border:1px solid color-mix(in srgb, var(--green) 40%, transparent); border-radius:999px; padding:5px 11px; white-space:nowrap; }
|
|
638
|
+
#rp-now.show,#rp-pause.show,#rp-again.show{ display:inline-block; }
|
|
639
|
+
html:not([data-theme="light"]) #rp-now,html:not([data-theme="light"]) #rp-pause,html:not([data-theme="light"]) #rp-again{ box-shadow:0 0 12px rgba(61,255,122,.15); }
|
|
588
640
|
|
|
589
641
|
/* ---- agents rail — the ONLY thing beside the brain, rightmost ---- */
|
|
590
642
|
#agentscol{
|
|
@@ -768,7 +820,7 @@
|
|
|
768
820
|
/* capture health — phase 2: per machine × harness rows from /distill
|
|
769
821
|
accounting (posts/sessions/MB/held); the phase-1 counts-only rows remain
|
|
770
822
|
as the degrade for old servers / nothing recorded yet */
|
|
771
|
-
.cap-row2{ display:flex; align-items:center; gap:9px; padding:2.5px 0; border-bottom:1px solid color-mix(in srgb, var(--line) 60%, transparent); }
|
|
823
|
+
.cap-row2{ display:flex; flex-wrap:wrap; align-items:center; gap:1px 9px; padding:2.5px 0; border-bottom:1px solid color-mix(in srgb, var(--line) 60%, transparent); }
|
|
772
824
|
.cap-row2:last-of-type{ border-bottom:none; }
|
|
773
825
|
.cap-dot{ width:6px; height:6px; border-radius:50%; flex:none; background:var(--green-mid); }
|
|
774
826
|
.cap-row2 .hn{ font:11px var(--mono); color:var(--text); flex:0 0 148px; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
|
|
@@ -779,6 +831,12 @@
|
|
|
779
831
|
.cap-bar .fill{ height:100%; border-radius:2.5px; background:var(--green-mid); }
|
|
780
832
|
.cap-row2 .st{ font-size:10px; color:var(--faint); font-family:var(--mono); white-space:nowrap; }
|
|
781
833
|
.cap-row2 .st b{ color:var(--dim); font-weight:500; }
|
|
834
|
+
/* fix round 7: the newest-night sub-line on the rolling-window rows — a
|
|
835
|
+
full-basis child wraps under the row's primary line (the suffix does NOT
|
|
836
|
+
fit beside "N sess · X MB" without pushing past the card edge); same
|
|
837
|
+
faint mono tone, theme token only, both themes free. Rows without a
|
|
838
|
+
newest night stay single-line. */
|
|
839
|
+
.cap-row2 .cap-ton{ flex-basis:100%; text-align:right; font:10px var(--mono); color:var(--faint); line-height:1.1; }
|
|
782
840
|
.cap-held{ color:var(--amber); margin-left:5px; }
|
|
783
841
|
/* #423 phase 3: the capture-pause badge — the same amber family as the
|
|
784
842
|
held badge (an operator state, not an error) */
|
|
@@ -963,6 +1021,7 @@
|
|
|
963
1021
|
.brow{ grid-template-columns:1fr; }
|
|
964
1022
|
.mrow .sn{ font-size:10px; }
|
|
965
1023
|
#rp-label{ display:none; }
|
|
1024
|
+
#replay{ flex-wrap:wrap; } /* #452: range pills + controls wrap rather than crush the track */
|
|
966
1025
|
#rp-dates span:nth-child(n+3){ display:none; }
|
|
967
1026
|
.acct-trigger .who{ display:none; }
|
|
968
1027
|
.field-head{ padding:8px 12px 7px; }
|
|
@@ -1180,13 +1239,17 @@
|
|
|
1180
1239
|
</div>
|
|
1181
1240
|
<div class="replay-foot">
|
|
1182
1241
|
<div id="replay">
|
|
1242
|
+
<div id="rp-range" role="group" aria-label="range"></div>
|
|
1183
1243
|
<span id="rp-label">nights</span>
|
|
1184
1244
|
<div id="rp-track">
|
|
1185
1245
|
<div id="rp-rail"></div>
|
|
1186
1246
|
<div id="rp-fill"></div>
|
|
1187
1247
|
<div id="rp-dates"></div>
|
|
1188
1248
|
<div id="rp-cursor"></div>
|
|
1249
|
+
<span id="rp-date"></span>
|
|
1189
1250
|
</div>
|
|
1251
|
+
<button id="rp-pause">pause</button>
|
|
1252
|
+
<button id="rp-again">replay again</button>
|
|
1190
1253
|
<button id="rp-now">return to now</button>
|
|
1191
1254
|
</div>
|
|
1192
1255
|
</div>
|
|
@@ -1307,7 +1370,7 @@ if(STILL){ document.body.classList.remove('booting'); document.body.classList.ad
|
|
|
1307
1370
|
/* =====================================================================
|
|
1308
1371
|
The approved #409 r6-flight engine, ported to live data. One canvas,
|
|
1309
1372
|
three verbs (look / travel / time) plus the quiet fourth: WATCH — ambient
|
|
1310
|
-
signals loop slowly along REAL stored links,
|
|
1373
|
+
signals loop slowly along REAL stored links, always on.
|
|
1311
1374
|
Stages are DERIVED presentation (server-side via /dashboard/field) over
|
|
1312
1375
|
the one numeric strength signal — never stored state.
|
|
1313
1376
|
===================================================================== */
|
|
@@ -1424,9 +1487,12 @@ function bubbleRadius(s){ return 6 + Math.sqrt(clamp(s??0,0,1))*3; }
|
|
|
1424
1487
|
function depthSizeDivisor(dz){ return Math.pow(Math.max(.14,dz),0.35); }
|
|
1425
1488
|
|
|
1426
1489
|
/* ---------- live-data state ---------- */
|
|
1427
|
-
let
|
|
1490
|
+
let RANGE=30; // days — the range selector's value (#452; 30-day default for
|
|
1491
|
+
// ALL views, owner directive 2026-09-16). NO persistence: every
|
|
1492
|
+
// load starts at 30 — it loads fast; longer is opt-in per click.
|
|
1493
|
+
let D=null; // /dashboard/data?range=RANGE d — band, series, digest
|
|
1428
1494
|
let F=null; // /dashboard/field
|
|
1429
|
-
let EV=null; // /dashboard/events?days=
|
|
1495
|
+
let EV=null; // /dashboard/events?days=RANGE — the replay ledger
|
|
1430
1496
|
let M=null; // /dashboard/model (#422) — null on failure: label-only degrade, no configure pill
|
|
1431
1497
|
let TOTAL=0, removedNow=0;
|
|
1432
1498
|
/* the store's static LIVE count (headline.live_memories ?? total): the
|
|
@@ -1637,13 +1703,19 @@ function buildWorld(){
|
|
|
1637
1703
|
|
|
1638
1704
|
// the flattened replay ledger (events within a night fire in cruise order);
|
|
1639
1705
|
// added/merged reuse the staggered born/merge times so blooms and births
|
|
1640
|
-
// coincide; enriched/linked carry their own salted staggers.
|
|
1706
|
+
// coincide; enriched/linked carry their own salted staggers. #452 adds the
|
|
1707
|
+
// truth-management captions — stagger order enriched .55 < retracted .65 <
|
|
1708
|
+
// superseded .70 < rewritten .75 < learned .80 keeps the cruise sane (each
|
|
1709
|
+
// new type gets its own salt, so per-id positions never collide).
|
|
1641
1710
|
EVENTS = [];
|
|
1642
1711
|
NIGHTS.forEach((n,i)=>{
|
|
1643
1712
|
for(const id of n.added) EVENTS.push({t:bornOf.get(id), type:'learned', id, cap:'Learned — “'+trunc(titleOf(id),52)+'”'});
|
|
1644
1713
|
for(const id of n.enriched) EVENTS.push({t:i+.55+stag(id,19)*.08, type:'enriched', id, cap:'Enriched — “'+trunc(titleOf(id),52)+'”'});
|
|
1645
1714
|
for(const mg of n.merged) EVENTS.push({t:mergeOf.get(mg.loser).t, type:'merged', loser:mg.loser, id:mg.loser, cap:'Merged — “'+trunc(titleOf(mg.loser),40)+'”'});
|
|
1646
1715
|
for(const lk of n.linked) EVENTS.push({t:i+.90+stag(lk.a+lk.b,23)*.08, type:'linked', a:lk.a, b:lk.b, cap:null});
|
|
1716
|
+
for(const sp of n.superseded) EVENTS.push({t:i+.70+stag(sp.old,29)*.08, type:'superseded', id:sp.old, cap:'Superseded — “'+trunc(titleOf(sp.old),52)+'”'});
|
|
1717
|
+
for(const rt of n.retracted) EVENTS.push({t:i+.65+stag(rt.old,31)*.08, type:'retracted', id:rt.old, cap:'Retracted — “'+trunc(titleOf(rt.old),52)+'”'});
|
|
1718
|
+
for(const id of n.rewritten) EVENTS.push({t:i+.75+stag(id,37)*.08, type:'rewritten', id, cap:'Rewritten — “'+trunc(titleOf(id),52)+'”'});
|
|
1647
1719
|
});
|
|
1648
1720
|
EVENTS.sort((x,y)=>x.t-y.t);
|
|
1649
1721
|
|
|
@@ -2487,14 +2559,21 @@ function toast(msg, ms){
|
|
|
2487
2559
|
function wake(){ lastActivity=performance.now(); }
|
|
2488
2560
|
|
|
2489
2561
|
/* ---------- replay — time travel: drag to take the helm, else the G1
|
|
2490
|
-
auto-cruise walks the REAL event ledger (one memory action at a time
|
|
2491
|
-
|
|
2562
|
+
auto-cruise walks the REAL event ledger (one memory action at a time)
|
|
2563
|
+
ONCE to today, then rests there (#452, owner ruling 2026-09-16 —
|
|
2564
|
+
supersedes the 2026-09-13 auto-loop). Pause/resume + "replay again" sit
|
|
2565
|
+
in the foot beside "return to now"; a manual take still pauses the
|
|
2566
|
+
cruise and re-engages ~12 s after idle, continuing toward today — where
|
|
2567
|
+
it now stops instead of looping.
|
|
2492
2568
|
With fewer than 2 nights the instrument renders its "now" state and
|
|
2493
2569
|
disables itself (degrade quietly). ---------- */
|
|
2494
2570
|
const track=el('rp-track');
|
|
2495
2571
|
function trackFrac(e){ const r=track.getBoundingClientRect(); return clamp((e.clientX-r.left)/r.width,0,1); }
|
|
2496
2572
|
let autoPlay=false, autoEvIdx=0, autoNextAt=0, manualUntil=3600, pendingApply=null;
|
|
2573
|
+
let paused=false; /* #452: pause holds the cruise position; resume continues */
|
|
2574
|
+
let played=false; /* #452: a full playback completed → rest at today, never loop */
|
|
2497
2575
|
function manualTake(){ autoPlay=false; pendingApply=null; manualUntil=performance.now()+12000; wake(); }
|
|
2576
|
+
function setPaused(v){ paused=v; el('rp-pause').textContent=paused?'resume':'pause'; }
|
|
2498
2577
|
/* HERALD — before each cruise step's change, a bright pulse flies in along
|
|
2499
2578
|
a REAL link touching the target (else from its nearest same-domain
|
|
2500
2579
|
neighbor) and LANDS: the update we see is the arrival */
|
|
@@ -2518,18 +2597,25 @@ function heraldTo(id){
|
|
|
2518
2597
|
signals.push({ path:p, i:0, s:0, dur:.45, tail:[], showcase:true, herald:true }); /* dur is seconds */
|
|
2519
2598
|
}
|
|
2520
2599
|
function autoTick(now){
|
|
2521
|
-
if(REDUCED||booting||!REPLAY_OK) return;
|
|
2600
|
+
if(REDUCED||booting||!REPLAY_OK||paused) return;
|
|
2522
2601
|
if(!autoPlay){ if(now>manualUntil && !scrubbing) autoPlay=true; else return; }
|
|
2523
2602
|
if(pendingApply){
|
|
2524
2603
|
if(now>=pendingApply.at){ seek(pendingApply.t); pendingApply=null; autoNextAt=now+820; }
|
|
2525
2604
|
return; /* the herald is in flight */
|
|
2526
2605
|
}
|
|
2527
2606
|
if(now<autoNextAt) return;
|
|
2528
|
-
if(T>=NOW_T-.001){
|
|
2607
|
+
if(T>=NOW_T-.001){
|
|
2608
|
+
/* a beat at "now": re-kick to the range start ONLY before the first
|
|
2609
|
+
full playback; after it, REST here — plays once, never loops (#452) */
|
|
2610
|
+
if(played){ autoPlay=false; autoNextAt=now+3200; return; }
|
|
2529
2611
|
autoEvIdx=0; autoNextAt=now+3200; seek(.001); return;
|
|
2530
2612
|
}
|
|
2531
2613
|
while(autoEvIdx<EVENTS.length && EVENTS[autoEvIdx].t<=T+.0001) autoEvIdx++;
|
|
2532
|
-
if(autoEvIdx>=EVENTS.length){
|
|
2614
|
+
if(autoEvIdx>=EVENTS.length){
|
|
2615
|
+
/* ledger exhausted: arrive at today and complete the playback (the
|
|
2616
|
+
flags go BEFORE the seek so onTChanged's control swap sees them) */
|
|
2617
|
+
autoNextAt=now+3200; played=true; autoPlay=false; seek(WINDOW); return;
|
|
2618
|
+
}
|
|
2533
2619
|
const ev=EVENTS[autoEvIdx++];
|
|
2534
2620
|
if(ev.id && signals.length<8){ heraldTo(ev.id); pendingApply={t:ev.t+.001, at:now+430}; }
|
|
2535
2621
|
else { seek(ev.t+.001); autoNextAt=now+820; }
|
|
@@ -2550,7 +2636,10 @@ function onTChanged(fromSeek){
|
|
|
2550
2636
|
const b=mems.get(ev.id);
|
|
2551
2637
|
if(!b||!aliveAt(b,ev.t)||b._sx===undefined) continue;
|
|
2552
2638
|
if(blooms.length>=6) break;
|
|
2553
|
-
|
|
2639
|
+
/* #452: superseded/retracted bloom in the FADING color (demoted
|
|
2640
|
+
claims); rewritten falls to the default truth color (a rewrite is
|
|
2641
|
+
the claim surviving, corrected) */
|
|
2642
|
+
const rgb= ev.type==='merged'||ev.type==='superseded'||ev.type==='retracted'? PAL.stages.fading.rgb : (ev.type==='learned'? PAL.stages.forming.rgb : PAL.stages.truth.rgb);
|
|
2554
2643
|
blooms.push({x:b._sx,y:b._sy,r0:2,r1:24+b._sr,t0:performance.now(),dur:1400,cap:ev.cap,rgb});
|
|
2555
2644
|
}
|
|
2556
2645
|
}
|
|
@@ -2559,6 +2648,18 @@ function onTChanged(fromSeek){
|
|
|
2559
2648
|
el('rp-cursor').style.left=(T/WINDOW*100)+'%';
|
|
2560
2649
|
const isNow=T>=NOW_T-.001;
|
|
2561
2650
|
el('rp-now').classList.toggle('show',!isNow&&REPLAY_OK);
|
|
2651
|
+
/* #452 date label above the scrub dot — same left % as the cursor, the
|
|
2652
|
+
night being viewed ("now" at the end); hidden when there is no ledger */
|
|
2653
|
+
const dlab=el('rp-date');
|
|
2654
|
+
if(REPLAY_OK&&NIGHTS.length){
|
|
2655
|
+
dlab.style.left=(T/WINDOW*100)+'%';
|
|
2656
|
+
dlab.textContent=isNow?'now':fmtDay(NIGHTS[Math.min(Math.floor(T),NIGHTS.length-1)].date);
|
|
2657
|
+
dlab.classList.add('show');
|
|
2658
|
+
}else dlab.classList.remove('show');
|
|
2659
|
+
/* #452 lifecycle pills: pause while a playback is live, "replay again"
|
|
2660
|
+
once it completed — at most ONE of them beside "return to now" */
|
|
2661
|
+
el('rp-pause').classList.toggle('show',REPLAY_OK&&!played);
|
|
2662
|
+
el('rp-again').classList.toggle('show',REPLAY_OK&&played);
|
|
2562
2663
|
updateMeasures();
|
|
2563
2664
|
/* #422 owner ruling: the overview counter is STATIC (the store's live
|
|
2564
2665
|
count, set once at boot + after writes) — scrubbing the replay no longer
|
|
@@ -2566,10 +2667,13 @@ function onTChanged(fromSeek){
|
|
|
2566
2667
|
dirty=true;
|
|
2567
2668
|
}
|
|
2568
2669
|
/* warp-to-now — accelerates through every remaining event, blooms firing,
|
|
2569
|
-
and arrives ~2.4 s later (ease in-out)
|
|
2670
|
+
and arrives ~2.4 s later (ease in-out). #452: arriving at now by hand
|
|
2671
|
+
completes the playback too — the cruise rests instead of looping after */
|
|
2570
2672
|
let warpUntil=0, warpFrom=0;
|
|
2571
2673
|
function warpToNow(){
|
|
2572
2674
|
manualTake();
|
|
2675
|
+
setPaused(false);
|
|
2676
|
+
played=true;
|
|
2573
2677
|
if(REDUCED||T>=NOW_T-.001||!REPLAY_OK){ seek(WINDOW); return; }
|
|
2574
2678
|
warpFrom=T; warpUntil=performance.now()+2400;
|
|
2575
2679
|
}
|
|
@@ -2582,6 +2686,72 @@ function warpTick(now){
|
|
|
2582
2686
|
}
|
|
2583
2687
|
el('rp-now').onclick=warpToNow;
|
|
2584
2688
|
|
|
2689
|
+
/* #452 — pause/resume + replay again. Pause holds the cruise position
|
|
2690
|
+
(autoTick returns early, pending heralds included); resume continues
|
|
2691
|
+
toward today. Replay again restarts from the range start and plays once.
|
|
2692
|
+
Visibility is onTChanged's job: pause renders only while a playback is
|
|
2693
|
+
live, "replay again" only once one completed — least clutter. */
|
|
2694
|
+
el('rp-pause').onclick=()=>{
|
|
2695
|
+
setPaused(!paused);
|
|
2696
|
+
if(!paused) autoPlay=true; /* resume continues the cruise immediately */
|
|
2697
|
+
wake();
|
|
2698
|
+
};
|
|
2699
|
+
el('rp-again').onclick=()=>{
|
|
2700
|
+
manualTake(); setPaused(false);
|
|
2701
|
+
played=false; autoEvIdx=0; pendingApply=null; autoPlay=true;
|
|
2702
|
+
seek(.001); wake();
|
|
2703
|
+
};
|
|
2704
|
+
|
|
2705
|
+
/* #452 — the range selector: 7/30/90/180 days (the owner-fixed option
|
|
2706
|
+
set), default 30, NO persistence — every load starts at 30 (loads fast).
|
|
2707
|
+
A click refetches BOTH range-scoped sources and rebuilds the world
|
|
2708
|
+
exactly like boot — the agents rail included (its "last night" line
|
|
2709
|
+
reads NIGHTS, so it must follow the new window); the replay then
|
|
2710
|
+
auto-starts on the new range via the idle re-engage (mirrors boot).
|
|
2711
|
+
Fail-soft: a failed fetch toasts, keeps the OLD data and the OLD pills
|
|
2712
|
+
— never a half-switched view. One switch at a time (refreshAfterWrite's
|
|
2713
|
+
refreshInFlight pattern): a click while a switch is in flight is
|
|
2714
|
+
IGNORED — a racing second fetch could resolve out of order and leave
|
|
2715
|
+
pills and data disagreeing. */
|
|
2716
|
+
const RANGE_OPTIONS=[7,30,90,180];
|
|
2717
|
+
function renderRangePills(){
|
|
2718
|
+
const host=el('rp-range'); host.innerHTML='';
|
|
2719
|
+
for(const n of RANGE_OPTIONS){
|
|
2720
|
+
const b=document.createElement('button');
|
|
2721
|
+
b.type='button'; b.className='rp-seg'; b.textContent=n+'d';
|
|
2722
|
+
b.title='last '+n+' days';
|
|
2723
|
+
b.setAttribute('aria-pressed', String(n===RANGE));
|
|
2724
|
+
b.onclick=()=>{ if(n!==RANGE) switchRange(n); };
|
|
2725
|
+
host.appendChild(b);
|
|
2726
|
+
}
|
|
2727
|
+
}
|
|
2728
|
+
let rangeSwitchInFlight=false;
|
|
2729
|
+
async function switchRange(n){
|
|
2730
|
+
if(rangeSwitchInFlight) return; rangeSwitchInFlight=true;
|
|
2731
|
+
const prev=RANGE; RANGE=n; renderRangePills();
|
|
2732
|
+
try{
|
|
2733
|
+
const [dd,ee]=await Promise.all([
|
|
2734
|
+
api('/dashboard/data?range='+RANGE+'d'),
|
|
2735
|
+
api('/dashboard/events?days='+RANGE),
|
|
2736
|
+
]);
|
|
2737
|
+
D=dd;
|
|
2738
|
+
if(ee&&Array.isArray(ee.nights)){ EV=ee; NIGHTS=EV.nights; } else { NIGHTS=[]; }
|
|
2739
|
+
}catch(e){
|
|
2740
|
+
RANGE=prev; renderRangePills();
|
|
2741
|
+
toast('Range switch failed: '+e.message);
|
|
2742
|
+
return;
|
|
2743
|
+
}finally{
|
|
2744
|
+
rangeSwitchInFlight=false;
|
|
2745
|
+
}
|
|
2746
|
+
buildWorld(); buildPaths(); buildTimeline(); renderBand(); buildRoll(); buildCapture(); buildAgents();
|
|
2747
|
+
/* reset the replay over the new window (boot's pattern): rest at "now"
|
|
2748
|
+
first, the idle re-engage then walks the new range once from the start */
|
|
2749
|
+
T=WINDOW; lastT=WINDOW; played=false; autoEvIdx=0; pendingApply=null; autoPlay=false;
|
|
2750
|
+
setPaused(false);
|
|
2751
|
+
onTChanged(true);
|
|
2752
|
+
}
|
|
2753
|
+
renderRangePills();
|
|
2754
|
+
|
|
2585
2755
|
/* the timeline: dots per night (green when busy adding, grey when the
|
|
2586
2756
|
night merged ≥3 — the prototype's thresholds), date labels at the ends */
|
|
2587
2757
|
function buildTimeline(){
|
|
@@ -2594,6 +2764,7 @@ function buildTimeline(){
|
|
|
2594
2764
|
dots.style.cssText='position:absolute;inset:0;pointer-events:none;';
|
|
2595
2765
|
if(REPLAY_OK){
|
|
2596
2766
|
label.textContent=NIGHTS.length+' nights';
|
|
2767
|
+
el('replay').classList.remove('off'); /* a range switch can revive the instrument (#452) */
|
|
2597
2768
|
const s1=document.createElement('span'); s1.style.left='0%'; s1.style.transform='none';
|
|
2598
2769
|
s1.textContent=fmtDay(NIGHTS[0].date); dates.appendChild(s1);
|
|
2599
2770
|
const s2=document.createElement('span'); s2.style.left='100%'; s2.style.transform='translateX(-100%)';
|
|
@@ -2603,7 +2774,10 @@ function buildTimeline(){
|
|
|
2603
2774
|
d.style.left=((i+.5)/WINDOW*100)+'%';
|
|
2604
2775
|
if(mergedL[i]>=3) d.classList.add('w');
|
|
2605
2776
|
else if(learnedL[i]>=8) d.classList.add('g');
|
|
2606
|
-
d.title=fmtDay(n.date)+' — learned '+(learnedL[i]||0)+(enrichedL[i]?' · enriched '+enrichedL[i]:'')+(mergedL[i]?' · merged '+mergedL[i]:'')
|
|
2777
|
+
d.title=fmtDay(n.date)+' — learned '+(learnedL[i]||0)+(enrichedL[i]?' · enriched '+enrichedL[i]:'')+(mergedL[i]?' · merged '+mergedL[i]:'')
|
|
2778
|
+
+(n.superseded.length?' · superseded '+n.superseded.length:'')
|
|
2779
|
+
+(n.retracted.length?' · retracted '+n.retracted.length:'')
|
|
2780
|
+
+(n.rewritten.length?' · rewritten '+n.rewritten.length:'');
|
|
2607
2781
|
frag.appendChild(d);
|
|
2608
2782
|
});
|
|
2609
2783
|
}else{
|
|
@@ -3231,7 +3405,14 @@ function buildRoll(){
|
|
|
3231
3405
|
|
|
3232
3406
|
/* ---------- capture health — phase 2: per machine × harness rows from the
|
|
3233
3407
|
/dashboard/data capture_health accounting; the counts-only rows remain
|
|
3234
|
-
the degrade for old servers / nothing recorded yet
|
|
3408
|
+
the degrade for old servers / nothing recorded yet.
|
|
3409
|
+
Fix round 7 (owner ruling 2026-09-14 — "the normal 30 day as the other
|
|
3410
|
+
cards"): the card's face is the ROLLING window (capture_health
|
|
3411
|
+
window_rows, summed over the last window_days calendar days); the newest
|
|
3412
|
+
night rides as a per-row secondary suffix ("tonight: N sess" / the
|
|
3413
|
+
night's date when it is not today). Degradation ladder: pre-round-7
|
|
3414
|
+
server (no window_rows) → the newest-night view below; no activity rows
|
|
3415
|
+
at all → the counts-only rows. ---------- */
|
|
3235
3416
|
/* ---------- machine × harness grouping (#424 review fixes 4+5 + the owner's
|
|
3236
3417
|
model-B direction): source_agent is "harness/profile" and each context may
|
|
3237
3418
|
carry a source_machine stamp (migration v15+). The rows a stats card and
|
|
@@ -3343,6 +3524,72 @@ function buildCapture(){
|
|
|
3343
3524
|
host.innerHTML='';
|
|
3344
3525
|
const sub=el('cap-sub');
|
|
3345
3526
|
const ch=D&&D.capture_health?D.capture_health:null;
|
|
3527
|
+
/* fix round 7: the rolling-window view — the card shows the normal 30 day
|
|
3528
|
+
like the band's other cards. window_rows is ABSENT on a pre-round-7
|
|
3529
|
+
server (and empty when nothing is recorded) → fall through to the
|
|
3530
|
+
newest-night view / counts degrade below. */
|
|
3531
|
+
if(ch&&Array.isArray(ch.window_rows)&&ch.window_rows.length){
|
|
3532
|
+
const wd=ch.window_days||30;
|
|
3533
|
+
if(sub) sub.textContent='last '+wd+' days';
|
|
3534
|
+
/* group the window's machine × agent rows into machine × harness
|
|
3535
|
+
bundles — same grouping as every other card surface */
|
|
3536
|
+
const groups=new Map();
|
|
3537
|
+
for(const r of ch.window_rows){
|
|
3538
|
+
const agent=String(r.agent||'unknown');
|
|
3539
|
+
const harness=agent.split('/')[0]||agent;
|
|
3540
|
+
const key=(r.machine||'')+'|'+harness;
|
|
3541
|
+
let g=groups.get(key);
|
|
3542
|
+
if(!g){ g={machine:r.machine||null, harness, posts:0, sessions:0, bytes:0, held:0, retried:0, agents:[]}; groups.set(key,g); }
|
|
3543
|
+
g.posts+=r.posts||0; g.sessions+=r.sessions||0; g.bytes+=r.bytes||0;
|
|
3544
|
+
g.held+=r.held||0; g.retried+=r.retried||0;
|
|
3545
|
+
g.agents.push(agent+' — '+r.posts+' post'+(r.posts===1?'':'s')+' · '+r.sessions+' sess · '+mbFmt(r.bytes||0)
|
|
3546
|
+
+(r.held?' · '+r.held+' held':'')+(r.retried?' · '+r.retried+' retried':''));
|
|
3547
|
+
}
|
|
3548
|
+
/* newest-night secondary: per-bundle sessions + held off capture_health
|
|
3549
|
+
rows (the newest day with rows). held keys the badge — a held post is
|
|
3550
|
+
actionable NOW (the client retries it next run); the window's own
|
|
3551
|
+
held/retried live in the row tooltip. */
|
|
3552
|
+
const night=new Map();
|
|
3553
|
+
if(ch.day&&Array.isArray(ch.rows)) for(const r of ch.rows){
|
|
3554
|
+
const agent=String(r.agent||'unknown');
|
|
3555
|
+
const harness=agent.split('/')[0]||agent;
|
|
3556
|
+
const key=(r.machine||'')+'|'+harness;
|
|
3557
|
+
const prev=night.get(key)||{sessions:0,held:0};
|
|
3558
|
+
prev.sessions+=r.sessions||0; prev.held+=r.held||0;
|
|
3559
|
+
night.set(key,prev);
|
|
3560
|
+
}
|
|
3561
|
+
const today=new Date().toISOString().slice(0,10);
|
|
3562
|
+
const nightLabel=ch.day===today?'tonight':fmtDay(ch.day);
|
|
3563
|
+
const gs2=[...groups.values()].sort((a,b)=>b.bytes-a.bytes);
|
|
3564
|
+
const maxB=gs2[0].bytes;
|
|
3565
|
+
const pausedKeys=fleetPausesByKey();
|
|
3566
|
+
for(const g of gs2){
|
|
3567
|
+
const n=night.get((g.machine||'')+'|'+g.harness);
|
|
3568
|
+
const row=document.createElement('div');
|
|
3569
|
+
row.className='cap-row2';
|
|
3570
|
+
const label=g.machine?g.machine+' · '+g.harness:g.harness;
|
|
3571
|
+
const paused=pausedKeys.has((g.machine||'')+'|'+g.harness);
|
|
3572
|
+
row.title=label+' — last '+wd+' days: '+fmt(g.sessions)+' sessions · '+mbFmt(g.bytes)+' posted'
|
|
3573
|
+
+(g.held>0?' · '+g.held+' held in window':'')
|
|
3574
|
+
+(g.retried>0?' · '+g.retried+' retried in window':'')
|
|
3575
|
+
+(n?' · '+nightLabel+': '+n.sessions+' sess'+(n.held>0?' ('+n.held+' held)':''):'')
|
|
3576
|
+
+(paused?' · CAPTURE PAUSED (posts are skipped — sessions are not backfilled)':'')
|
|
3577
|
+
+':\n'+g.agents.join('\n');
|
|
3578
|
+
row.innerHTML='<span class="cap-dot"></span>'+
|
|
3579
|
+
'<span class="hn" title="'+esc(label)+'">'+esc(label)+'</span>'+
|
|
3580
|
+
'<span class="cap-bar"><span class="fill" style="width:'+(g.bytes/Math.max(maxB,1)*100)+'%"></span></span>'+
|
|
3581
|
+
'<span class="st"><b>'+fmt(g.sessions)+'</b> sess · '+mbFmt(g.bytes)
|
|
3582
|
+
+(paused?'<span class="cap-paused" title="capture paused — posts are skipped (200) and sessions are not backfilled">PAUSED</span>':'')
|
|
3583
|
+
+(n&&n.held>0?'<span class="cap-held" title="'+nightLabel+' — failed posts the client will retry — cursor held">⚠ '+n.held+' held</span>':'')
|
|
3584
|
+
+'</span>'
|
|
3585
|
+
/* the newest-night sub-line — a full-basis flex child, so it wraps
|
|
3586
|
+
UNDER the primary line (the suffix never fits beside it; see the
|
|
3587
|
+
.cap-ton rule) and only exists for bundles with newest-night rows */
|
|
3588
|
+
+(n?'<span class="cap-ton" title="newest capture night ('+nightLabel+') — '+n.sessions+' session'+(n.sessions===1?'':'s')+' posted that night">'+nightLabel+': '+n.sessions+' sess</span>':'');
|
|
3589
|
+
host.appendChild(row);
|
|
3590
|
+
}
|
|
3591
|
+
return;
|
|
3592
|
+
}
|
|
3346
3593
|
if(ch&&Array.isArray(ch.rows)&&ch.rows.length){
|
|
3347
3594
|
/* phase-2 live view: the /distill accounting rows, grouped machine ×
|
|
3348
3595
|
harness — width encodes capture volume (each bundle's byte share of
|
|
@@ -3421,7 +3668,9 @@ function buildCapture(){
|
|
|
3421
3668
|
function lastNightByAgent(){
|
|
3422
3669
|
for(let i=NIGHTS.length-1;i>=0;i--){
|
|
3423
3670
|
const n=NIGHTS[i];
|
|
3424
|
-
|
|
3671
|
+
/* #452: the truth-management events count too — a superseded-only night
|
|
3672
|
+
is a real night */
|
|
3673
|
+
if(n.added.length+n.enriched.length+n.merged.length+n.linked.length+n.superseded.length+n.retracted.length+n.rewritten.length>0) return {date:n.date,by:n.by_agent};
|
|
3425
3674
|
}
|
|
3426
3675
|
return null;
|
|
3427
3676
|
}
|
|
@@ -3659,7 +3908,7 @@ function buildAgents(){
|
|
|
3659
3908
|
* counts — the paused state and dots re-derive from the fresh payload. */
|
|
3660
3909
|
async function refreshFleet(){
|
|
3661
3910
|
try{
|
|
3662
|
-
const dd=await api('/dashboard/data?range=
|
|
3911
|
+
const dd=await api('/dashboard/data?range='+RANGE+'d');
|
|
3663
3912
|
D=dd;
|
|
3664
3913
|
buildAgents();
|
|
3665
3914
|
buildCapture();
|
|
@@ -4040,7 +4289,7 @@ let refreshInFlight=false;
|
|
|
4040
4289
|
async function refreshAfterWrite(){
|
|
4041
4290
|
if(refreshInFlight) return; refreshInFlight=true;
|
|
4042
4291
|
try{
|
|
4043
|
-
const [ff,dd]=await Promise.all([api('/dashboard/field'),api('/dashboard/data?range=
|
|
4292
|
+
const [ff,dd]=await Promise.all([api('/dashboard/field'),api('/dashboard/data?range='+RANGE+'d').catch(()=>null)]);
|
|
4044
4293
|
if(ff){ F=ff; buildWorld(); }
|
|
4045
4294
|
if(dd){ D=dd; }
|
|
4046
4295
|
renderBand(); buildRoll(); buildCapture(); renderLegend(); renderFeel();
|
|
@@ -4351,9 +4600,9 @@ async function pollHealth(){
|
|
|
4351
4600
|
===================================================================== */
|
|
4352
4601
|
async function boot(){
|
|
4353
4602
|
const [dd,ff,ee,hh,hd,mm]=await Promise.allSettled([
|
|
4354
|
-
api('/dashboard/data?range=
|
|
4603
|
+
api('/dashboard/data?range='+RANGE+'d'),
|
|
4355
4604
|
api('/dashboard/field'),
|
|
4356
|
-
api('/dashboard/events?days=
|
|
4605
|
+
api('/dashboard/events?days='+RANGE),
|
|
4357
4606
|
fetch('/health'),
|
|
4358
4607
|
api('/health/detail'),
|
|
4359
4608
|
api('/dashboard/model'),
|
package/dist/calibration.d.ts
CHANGED
|
@@ -28,6 +28,36 @@
|
|
|
28
28
|
* ranking. Long-term remembering is the product; time preference stays mild.
|
|
29
29
|
*/
|
|
30
30
|
export declare const DECAY_HALF_LIFE_DAYS = 365;
|
|
31
|
+
/**
|
|
32
|
+
* Per-use strength promotion rate (#448, the strength model's upward path):
|
|
33
|
+
* one application of `promotion = PROMOTION_RATE × (1 − S / IMPORTANCE_CEILING)
|
|
34
|
+
* × S^(−0.3)` per new use (S = stored base_strength), iterated once per
|
|
35
|
+
* access-count delta by the nightly stagePromotion stage and clamped at the
|
|
36
|
+
* ceiling. Calibrated so the first access on a median-0.35 memory gives ~+0.03
|
|
37
|
+
* (0.35 → 0.3786). Shape grounded in LTP saturation curves (Cao & Harris
|
|
38
|
+
* 2014), the power law of practice (α ≈ 0.3, Newell & Rosenbloom 1981), and
|
|
39
|
+
* spaced-repetition stability multipliers (S^−0.53, SuperMemo SM-17,
|
|
40
|
+
* n > 60,000 real repetitions): bigger boosts for weaker memories,
|
|
41
|
+
* saturating near the ceiling, never fully stopping (asymptotic). The decay
|
|
42
|
+
* side is untouched — a memory's fade RATE no longer depends on its use or
|
|
43
|
+
* link history (the #448 hardening removal); use raises the STORED score
|
|
44
|
+
* instead, and abandonment fades it on the same 365-day clock as everything
|
|
45
|
+
* else. RELEASE-MANAGED per this module's evolution contract — no config key.
|
|
46
|
+
*/
|
|
47
|
+
export declare const PROMOTION_RATE = 0.033;
|
|
48
|
+
/**
|
|
49
|
+
* Lower bound on the promotion formula's S input (#453 review Minor finding,
|
|
50
|
+
* owner decision 2026-09-16). base_strength 0.0 is a writable value (legacy
|
|
51
|
+
* rows, operator edits), and S^(−0.3) has a zero-singularity: unfloored, one
|
|
52
|
+
* access on a 0.0 row computed delta = 0.033 × (1 − 0/0.95) × 0^−0.3 =
|
|
53
|
+
* Infinity, and the ceiling clamp turned that into a leap straight to 0.95.
|
|
54
|
+
* Floored at 0.01, the same access lands at 0.033 × (1 − 0.01/0.95) ×
|
|
55
|
+
* 0.01^(−0.3) ≈ +0.13 (0.0 → ≈0.14) — the biggest first boost the formula
|
|
56
|
+
* can give, bounded and far from the ceiling. The floor clamps the FORMULA
|
|
57
|
+
* INPUT only: storage keeps a 0.0 row at 0.0 until it is used, and the
|
|
58
|
+
* promoted result is nonzero from then on. RELEASE-MANAGED like PROMOTION_RATE.
|
|
59
|
+
*/
|
|
60
|
+
export declare const PROMOTION_STRENGTH_FLOOR = 0.01;
|
|
31
61
|
/** Default k for retrieve() (/search without an explicit limit). #192. */
|
|
32
62
|
export declare const SEARCH_LIMIT = 8;
|
|
33
63
|
/** Default k for searchRecent() (/recent without an explicit limit). #192. */
|
package/dist/calibration.js
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
* the removal is never silent.
|
|
25
25
|
*/
|
|
26
26
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
27
|
-
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 = 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_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.DOMAIN_AFFINITY_WEIGHT = exports.PROJECT_AFFINITY_WEIGHT = exports.SUPERSEDED_DEMOTION = exports.FRESHNESS_BOOST_WEIGHT = exports.FRESHNESS_BOOST_DAYS = exports.SCORE_RECENCY_WEIGHT = exports.SCORE_CONNECTIONS_WEIGHT = exports.SCORE_STRENGTH_WEIGHT = exports.SCORE_SIMILARITY_WEIGHT = 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.DECAY_HALF_LIFE_DAYS = void 0;
|
|
27
|
+
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 = 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_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.DOMAIN_AFFINITY_WEIGHT = exports.PROJECT_AFFINITY_WEIGHT = exports.SUPERSEDED_DEMOTION = exports.FRESHNESS_BOOST_WEIGHT = exports.FRESHNESS_BOOST_DAYS = exports.SCORE_RECENCY_WEIGHT = exports.SCORE_CONNECTIONS_WEIGHT = exports.SCORE_STRENGTH_WEIGHT = exports.SCORE_SIMILARITY_WEIGHT = 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
28
|
exports.resolveNumCtx = resolveNumCtx;
|
|
29
29
|
exports.resolveOllamaFlushEvery = resolveOllamaFlushEvery;
|
|
30
30
|
exports.resolveOllamaFlushWaitMs = resolveOllamaFlushWaitMs;
|
|
@@ -39,6 +39,36 @@ exports.resolveOllamaFlushWaitMs = resolveOllamaFlushWaitMs;
|
|
|
39
39
|
* ranking. Long-term remembering is the product; time preference stays mild.
|
|
40
40
|
*/
|
|
41
41
|
exports.DECAY_HALF_LIFE_DAYS = 365;
|
|
42
|
+
/**
|
|
43
|
+
* Per-use strength promotion rate (#448, the strength model's upward path):
|
|
44
|
+
* one application of `promotion = PROMOTION_RATE × (1 − S / IMPORTANCE_CEILING)
|
|
45
|
+
* × S^(−0.3)` per new use (S = stored base_strength), iterated once per
|
|
46
|
+
* access-count delta by the nightly stagePromotion stage and clamped at the
|
|
47
|
+
* ceiling. Calibrated so the first access on a median-0.35 memory gives ~+0.03
|
|
48
|
+
* (0.35 → 0.3786). Shape grounded in LTP saturation curves (Cao & Harris
|
|
49
|
+
* 2014), the power law of practice (α ≈ 0.3, Newell & Rosenbloom 1981), and
|
|
50
|
+
* spaced-repetition stability multipliers (S^−0.53, SuperMemo SM-17,
|
|
51
|
+
* n > 60,000 real repetitions): bigger boosts for weaker memories,
|
|
52
|
+
* saturating near the ceiling, never fully stopping (asymptotic). The decay
|
|
53
|
+
* side is untouched — a memory's fade RATE no longer depends on its use or
|
|
54
|
+
* link history (the #448 hardening removal); use raises the STORED score
|
|
55
|
+
* instead, and abandonment fades it on the same 365-day clock as everything
|
|
56
|
+
* else. RELEASE-MANAGED per this module's evolution contract — no config key.
|
|
57
|
+
*/
|
|
58
|
+
exports.PROMOTION_RATE = 0.033;
|
|
59
|
+
/**
|
|
60
|
+
* Lower bound on the promotion formula's S input (#453 review Minor finding,
|
|
61
|
+
* owner decision 2026-09-16). base_strength 0.0 is a writable value (legacy
|
|
62
|
+
* rows, operator edits), and S^(−0.3) has a zero-singularity: unfloored, one
|
|
63
|
+
* access on a 0.0 row computed delta = 0.033 × (1 − 0/0.95) × 0^−0.3 =
|
|
64
|
+
* Infinity, and the ceiling clamp turned that into a leap straight to 0.95.
|
|
65
|
+
* Floored at 0.01, the same access lands at 0.033 × (1 − 0.01/0.95) ×
|
|
66
|
+
* 0.01^(−0.3) ≈ +0.13 (0.0 → ≈0.14) — the biggest first boost the formula
|
|
67
|
+
* can give, bounded and far from the ceiling. The floor clamps the FORMULA
|
|
68
|
+
* INPUT only: storage keeps a 0.0 row at 0.0 until it is used, and the
|
|
69
|
+
* promoted result is nonzero from then on. RELEASE-MANAGED like PROMOTION_RATE.
|
|
70
|
+
*/
|
|
71
|
+
exports.PROMOTION_STRENGTH_FLOOR = 0.01;
|
|
42
72
|
/** Default k for retrieve() (/search without an explicit limit). #192. */
|
|
43
73
|
exports.SEARCH_LIMIT = 8;
|
|
44
74
|
/** Default k for searchRecent() (/recent without an explicit limit). #192. */
|