@dzhechkov/harness-core 0.3.109 → 0.3.110
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/learning-backend.d.ts +10 -0
- package/dist/learning-backend.d.ts.map +1 -1
- package/dist/learning-backend.js +18 -0
- package/dist/learning-backend.js.map +1 -1
- package/dist/patterns.d.ts +29 -0
- package/dist/patterns.d.ts.map +1 -1
- package/dist/patterns.js +74 -1
- package/dist/patterns.js.map +1 -1
- package/dist/publish.d.ts +7 -0
- package/dist/publish.d.ts.map +1 -1
- package/dist/publish.js +17 -1
- package/dist/publish.js.map +1 -1
- package/dist/safla-delta.d.ts +88 -0
- package/dist/safla-delta.d.ts.map +1 -0
- package/dist/safla-delta.js +131 -0
- package/dist/safla-delta.js.map +1 -0
- package/dist/vector-tier.d.ts.map +1 -1
- package/dist/vector-tier.js +17 -7
- package/dist/vector-tier.js.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +3 -2
- package/src/learning-backend.ts +26 -0
- package/src/patterns.ts +99 -2
- package/src/publish.ts +17 -1
- package/src/safla-delta.ts +203 -0
- package/src/vector-tier.ts +14 -8
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SAFLA Delta-Evaluation for dz lesson ranking (rUv-scout #2).
|
|
3
|
+
*
|
|
4
|
+
* Port of `safla/core/delta_evaluation.py` (grounded via search_ruvnet). SAFLA ranks a thing by the
|
|
5
|
+
* MEASURED CHANGE in its payoff over time — a slope — as a context-adaptive weighted sum of four temporal
|
|
6
|
+
* deltas. dz's lesson store ranks by a LEVEL (uses/recency/reward); this adds the slope.
|
|
7
|
+
*
|
|
8
|
+
* ADR-001 (features/safla-delta-eval): the four-delta STRUCTURE is preserved verbatim so the port is
|
|
9
|
+
* auditable against the source; only the deltas dz can MEASURE (performance, efficiency, stability) are
|
|
10
|
+
* driven by real signals. Capability is structurally 0 for a lesson (a lesson gains no "capabilities") and
|
|
11
|
+
* its weight is RENORMALIZED away — never fabricated. Every function here is total: no input throws.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/** Numeric guard from the source (`max(·, 1e-8)`). */
|
|
15
|
+
const EPS = 1e-8;
|
|
16
|
+
|
|
17
|
+
/** The raw SAFLA evaluation inputs (one snapshot). Fields absent → treated as their neutral default. */
|
|
18
|
+
export interface DeltaInput {
|
|
19
|
+
readonly reward?: number;
|
|
20
|
+
readonly tokensUsed?: number;
|
|
21
|
+
readonly throughput?: number;
|
|
22
|
+
readonly resourcesUsed?: number;
|
|
23
|
+
readonly variance?: number;
|
|
24
|
+
readonly capabilities?: number;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** The four per-axis deltas (SAFLA `DeltaMetrics`). */
|
|
28
|
+
export interface DeltaMetrics {
|
|
29
|
+
readonly performance: number;
|
|
30
|
+
readonly efficiency: number;
|
|
31
|
+
readonly stability: number;
|
|
32
|
+
readonly capability: number;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** SAFLA `AdaptiveWeights`. */
|
|
36
|
+
export interface AdaptiveWeights {
|
|
37
|
+
readonly performance: number;
|
|
38
|
+
readonly efficiency: number;
|
|
39
|
+
readonly stability: number;
|
|
40
|
+
readonly capability: number;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** SAFLA defaults (delta_evaluation.py `AdaptiveWeights`). */
|
|
44
|
+
export const DEFAULT_WEIGHTS: AdaptiveWeights = {
|
|
45
|
+
performance: 0.4,
|
|
46
|
+
efficiency: 0.3,
|
|
47
|
+
stability: 0.2,
|
|
48
|
+
capability: 0.1,
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const n = (x: number | undefined, d = 0): number => (typeof x === 'number' && isFinite(x) ? x : d);
|
|
52
|
+
|
|
53
|
+
// ── The four deltas, faithful to safla/core/delta_evaluation.py ──────────────
|
|
54
|
+
|
|
55
|
+
/** `(reward − prev_reward) / max(tokens_used, 1e-8)`. */
|
|
56
|
+
export function performanceDelta(cur: DeltaInput, prev: DeltaInput): number {
|
|
57
|
+
return (n(cur.reward) - n(prev.reward)) / Math.max(n(cur.tokensUsed, 1), EPS);
|
|
58
|
+
}
|
|
59
|
+
/** `(throughput − prev_throughput) / max(resources_used, 1e-8)`. */
|
|
60
|
+
export function efficiencyDelta(cur: DeltaInput, prev: DeltaInput): number {
|
|
61
|
+
return (n(cur.throughput) - n(prev.throughput)) / Math.max(n(cur.resourcesUsed, 1), EPS);
|
|
62
|
+
}
|
|
63
|
+
/** `prev_variance − variance` — variance REDUCTION is positive (lower variance is better). */
|
|
64
|
+
export function stabilityDelta(cur: DeltaInput, prev: DeltaInput): number {
|
|
65
|
+
return n(prev.variance) - n(cur.variance);
|
|
66
|
+
}
|
|
67
|
+
/** `capabilities − prev_capabilities`. Structurally 0 for a dz lesson (ADR-001). */
|
|
68
|
+
export function capabilityDelta(cur: DeltaInput, prev: DeltaInput): number {
|
|
69
|
+
return n(cur.capabilities) - n(prev.capabilities);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** SAFLA `AdaptiveWeights.adjust_for_context` — same four re-tilts, else the defaults. */
|
|
73
|
+
export function adjustForContext(context: string | null | undefined): AdaptiveWeights {
|
|
74
|
+
const c = (context ?? '').toLowerCase();
|
|
75
|
+
if (c.includes('performance')) return { performance: 0.6, efficiency: 0.2, stability: 0.1, capability: 0.1 };
|
|
76
|
+
if (c.includes('efficiency')) return { performance: 0.2, efficiency: 0.6, stability: 0.1, capability: 0.1 };
|
|
77
|
+
if (c.includes('stability')) return { performance: 0.2, efficiency: 0.1, stability: 0.6, capability: 0.1 };
|
|
78
|
+
if (c.includes('capability')) return { performance: 0.1, efficiency: 0.1, stability: 0.2, capability: 0.6 };
|
|
79
|
+
return DEFAULT_WEIGHTS;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Renormalize weights over the axes that carry a real signal (ADR-001, FR-4). `active.capability=false`
|
|
84
|
+
* (the dz default) redistributes the capability weight across the others so the effective weights still
|
|
85
|
+
* sum to 1 — the inert axis is neither fabricated nor silently value-dropped. Degenerate all-inactive →
|
|
86
|
+
* the input is returned unchanged (never divide by 0).
|
|
87
|
+
*/
|
|
88
|
+
export function renormalizeOverActive(
|
|
89
|
+
w: AdaptiveWeights,
|
|
90
|
+
active: Partial<Record<keyof AdaptiveWeights, boolean>> = { capability: false },
|
|
91
|
+
): AdaptiveWeights {
|
|
92
|
+
const on = (k: keyof AdaptiveWeights): boolean => active[k] !== false;
|
|
93
|
+
const sum = (['performance', 'efficiency', 'stability', 'capability'] as const)
|
|
94
|
+
.reduce((s, k) => s + (on(k) ? w[k] : 0), 0);
|
|
95
|
+
if (sum <= EPS) return w;
|
|
96
|
+
return {
|
|
97
|
+
performance: on('performance') ? w.performance / sum : 0,
|
|
98
|
+
efficiency: on('efficiency') ? w.efficiency / sum : 0,
|
|
99
|
+
stability: on('stability') ? w.stability / sum : 0,
|
|
100
|
+
capability: on('capability') ? w.capability / sum : 0,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** SAFLA `total_delta` — the weighted sum (batch_weighted_sum in the source). */
|
|
105
|
+
export function deltaEvaluate(cur: DeltaInput, prev: DeltaInput, weights: AdaptiveWeights = DEFAULT_WEIGHTS): number {
|
|
106
|
+
const m: DeltaMetrics = {
|
|
107
|
+
performance: performanceDelta(cur, prev),
|
|
108
|
+
efficiency: efficiencyDelta(cur, prev),
|
|
109
|
+
stability: stabilityDelta(cur, prev),
|
|
110
|
+
capability: capabilityDelta(cur, prev),
|
|
111
|
+
};
|
|
112
|
+
return (
|
|
113
|
+
weights.performance * m.performance +
|
|
114
|
+
weights.efficiency * m.efficiency +
|
|
115
|
+
weights.stability * m.stability +
|
|
116
|
+
weights.capability * m.capability
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// ── dz adapter: reinforce history → a lesson's delta score ───────────────────
|
|
121
|
+
|
|
122
|
+
/** One reinforce event from `.dz/sessions.jsonl` (`{ts, uses}`), plus the record's current reward. */
|
|
123
|
+
export interface ReinforceEvent {
|
|
124
|
+
/** Epoch millis. */
|
|
125
|
+
readonly t: number;
|
|
126
|
+
readonly uses: number;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** A lesson's ranking input: its reinforce history (oldest→newest) + current reward in [0,1]. */
|
|
130
|
+
export interface LessonHistory {
|
|
131
|
+
readonly id: string;
|
|
132
|
+
readonly reward: number;
|
|
133
|
+
/** Reinforce events, any order (sorted internally). */
|
|
134
|
+
readonly events: readonly ReinforceEvent[];
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** A lesson's delta score + whether it is a prune candidate (FR-5). */
|
|
138
|
+
export interface LessonDelta {
|
|
139
|
+
readonly id: string;
|
|
140
|
+
readonly delta: number;
|
|
141
|
+
/** True iff the delta is ≤ 0 over the window AND there was enough history to judge. */
|
|
142
|
+
readonly pruneCandidate: boolean;
|
|
143
|
+
/** False when < 2 events — an UNKNOWN slope scored a neutral 0, not a penalty (FR-3). */
|
|
144
|
+
readonly hasSignal: boolean;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const DAY_MS = 86_400_000;
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Score one lesson by SAFLA delta from its reinforce history (FR-1/3/4). Maps dz signals onto the source:
|
|
151
|
+
* efficiency = Δuses/Δdays (raw recall rate); performance = reward·(Δuses/Δdays) (reward-weighted rate,
|
|
152
|
+
* carried via `throughput`); stability = variance reduction across interval rates (needs ≥3 events);
|
|
153
|
+
* capability = 0 (renormalized out). < 2 events → neutral 0 (unknown slope).
|
|
154
|
+
*/
|
|
155
|
+
export function lessonDeltaFromHistory(
|
|
156
|
+
lesson: LessonHistory,
|
|
157
|
+
weights: AdaptiveWeights = DEFAULT_WEIGHTS,
|
|
158
|
+
): LessonDelta {
|
|
159
|
+
const ev = [...lesson.events].filter((e) => typeof e.t === 'number' && isFinite(e.t)).sort((a, b) => a.t - b.t);
|
|
160
|
+
if (ev.length < 2) return { id: lesson.id, delta: 0, pruneCandidate: false, hasSignal: false };
|
|
161
|
+
|
|
162
|
+
const reward = Math.min(1, Math.max(0, n(lesson.reward)));
|
|
163
|
+
// Per-interval recall rates (uses gained per day).
|
|
164
|
+
const rates: number[] = [];
|
|
165
|
+
for (let i = 1; i < ev.length; i++) {
|
|
166
|
+
const dUses = ev[i]!.uses - ev[i - 1]!.uses;
|
|
167
|
+
const dDays = Math.max((ev[i]!.t - ev[i - 1]!.t) / DAY_MS, EPS);
|
|
168
|
+
rates.push(dUses / dDays);
|
|
169
|
+
}
|
|
170
|
+
const curRate = rates[rates.length - 1]!;
|
|
171
|
+
const prevRate = rates.length >= 2 ? rates[rates.length - 2]! : 0;
|
|
172
|
+
|
|
173
|
+
// Variance of rates over the window (stability needs ≥2 rates i.e. ≥3 events; else 0 = no signal).
|
|
174
|
+
const variance = (xs: number[]): number => {
|
|
175
|
+
if (xs.length < 2) return 0;
|
|
176
|
+
const mean = xs.reduce((s, x) => s + x, 0) / xs.length;
|
|
177
|
+
return xs.reduce((s, x) => s + (x - mean) ** 2, 0) / xs.length;
|
|
178
|
+
};
|
|
179
|
+
const curVar = variance(rates);
|
|
180
|
+
const prevVar = variance(rates.slice(0, -1));
|
|
181
|
+
|
|
182
|
+
// dz mapping (ADR-001): efficiency = raw recall-rate change; performance = reward-weighted rate change;
|
|
183
|
+
// stability = variance REDUCTION of the rates; capability = 0 (structurally absent for a lesson).
|
|
184
|
+
const w = renormalizeOverActive(weights, { capability: false });
|
|
185
|
+
const m: DeltaMetrics = {
|
|
186
|
+
performance: reward * (curRate - prevRate),
|
|
187
|
+
efficiency: curRate - prevRate,
|
|
188
|
+
stability: prevVar - curVar,
|
|
189
|
+
capability: 0,
|
|
190
|
+
};
|
|
191
|
+
const delta =
|
|
192
|
+
w.performance * m.performance + w.efficiency * m.efficiency + w.stability * m.stability + w.capability * m.capability;
|
|
193
|
+
|
|
194
|
+
return { id: lesson.id, delta, pruneCandidate: delta <= 0, hasSignal: true };
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/** Rank lessons by SAFLA delta, highest slope first. Lessons with no signal (delta 0) sort as neutral. */
|
|
198
|
+
export function rankLessonsByDelta(
|
|
199
|
+
lessons: readonly LessonHistory[],
|
|
200
|
+
weights: AdaptiveWeights = DEFAULT_WEIGHTS,
|
|
201
|
+
): readonly LessonDelta[] {
|
|
202
|
+
return lessons.map((l) => lessonDeltaFromHistory(l, weights)).sort((a, b) => b.delta - a.delta);
|
|
203
|
+
}
|
package/src/vector-tier.ts
CHANGED
|
@@ -46,6 +46,7 @@ import {
|
|
|
46
46
|
patternRecordId,
|
|
47
47
|
patternIdentityOf,
|
|
48
48
|
dreamRecordId,
|
|
49
|
+
lessonDeltaMap,
|
|
49
50
|
loadStoreRecords,
|
|
50
51
|
readMemoryLearningConfig,
|
|
51
52
|
readReinforcementState,
|
|
@@ -65,7 +66,7 @@ import {
|
|
|
65
66
|
reindexAgentdbRows,
|
|
66
67
|
} from './agentdb-index.js';
|
|
67
68
|
import { currentEmbedManifest, guardEmbedSpace, DEFAULT_EMBED_DIM, resolveEmbedModel, type EmbedModelConfig } from './embedding-config.js';
|
|
68
|
-
import { applyLearningSignals, resolveLearningBackend, type LearningSignalBackend } from './learning-backend.js';
|
|
69
|
+
import { applyLearningSignals, applyLearningSignalsWithDelta, resolveLearningBackend, type LearningSignalBackend } from './learning-backend.js';
|
|
69
70
|
|
|
70
71
|
/* ------------------------------------------------------------------ */
|
|
71
72
|
/* Types (04_domain_model §3.4 / §4.1) */
|
|
@@ -787,16 +788,21 @@ export async function recallHybrid(
|
|
|
787
788
|
}
|
|
788
789
|
const idOf = (p: PatternRecord): string => identityToId.get(patternIdentityOf(p)) ?? patternRecordId(p);
|
|
789
790
|
const learning = resolveLearningBackend(projectRoot);
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
791
|
+
// Phase 3: opt-in SAFLA-delta re-rank. The map is built ONCE per recall (off ⇒ undefined ⇒ the
|
|
792
|
+
// reinforce-only path, byte-identical to today).
|
|
793
|
+
const deltaMap = readMemoryLearningConfig(projectRoot).deltaRerank ? lessonDeltaMap(projectRoot) : undefined;
|
|
794
|
+
const enhance = (hits: readonly HybridHit[]): HybridHit[] => {
|
|
795
|
+
const candidates = hits.map((h) => {
|
|
794
796
|
const dzId = idOf(h.pattern);
|
|
795
797
|
const rec = idToRecord.get(dzId);
|
|
796
798
|
return { dzId, score: h.score, reinforcement: rec !== undefined ? readReinforcementState(rec) : undefined };
|
|
797
|
-
})
|
|
798
|
-
|
|
799
|
-
|
|
799
|
+
});
|
|
800
|
+
if (deltaMap !== undefined) {
|
|
801
|
+
const deltaByIndex = candidates.map((c) => deltaMap.get(c.dzId) ?? 0);
|
|
802
|
+
return applyLearningSignalsWithDelta(hits, learning, candidates, REINFORCE_RRF_CAP, deltaByIndex, REINFORCE_RRF_CAP);
|
|
803
|
+
}
|
|
804
|
+
return applyLearningSignals(hits, learning, candidates, REINFORCE_RRF_CAP);
|
|
805
|
+
};
|
|
800
806
|
const lexicalOnly = (extra: Partial<Pick<HybridRecall, 'vectorEngine' | 'vectorReason' | 'vectorError'>>): HybridRecall => ({
|
|
801
807
|
hits: enhance(lexical.map((h, rank) => ({ pattern: h.pattern, backend: h.backend, score: 1 / (RRF_K + rank + 1) }))),
|
|
802
808
|
lexicalBackend,
|