@dzhechkov/harness-core 0.7.11 → 0.8.1
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/.dz-manifest.json +287 -87
- package/README.md +60 -1
- package/dist/amendment-trace.d.ts +12 -1
- package/dist/amendment-trace.d.ts.map +1 -1
- package/dist/amendment-trace.js +22 -4
- package/dist/amendment-trace.js.map +1 -1
- package/dist/book-kb.d.ts.map +1 -1
- package/dist/book-kb.js +17 -0
- package/dist/book-kb.js.map +1 -1
- package/dist/feature-adr-checkpoints.d.ts +61 -0
- package/dist/feature-adr-checkpoints.d.ts.map +1 -1
- package/dist/feature-adr-checkpoints.js +116 -2
- package/dist/feature-adr-checkpoints.js.map +1 -1
- package/dist/feature-adr-routing.d.ts +69 -12
- package/dist/feature-adr-routing.d.ts.map +1 -1
- package/dist/feature-adr-routing.js +117 -7
- package/dist/feature-adr-routing.js.map +1 -1
- package/dist/index.d.ts +23 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23 -4
- package/dist/index.js.map +1 -1
- package/dist/learning-backend.d.ts +39 -0
- package/dist/learning-backend.d.ts.map +1 -1
- package/dist/learning-backend.js +31 -11
- package/dist/learning-backend.js.map +1 -1
- package/dist/lesson-bandit.d.ts +116 -0
- package/dist/lesson-bandit.d.ts.map +1 -0
- package/dist/lesson-bandit.js +235 -0
- package/dist/lesson-bandit.js.map +1 -0
- package/dist/lesson-payoff.d.ts +260 -0
- package/dist/lesson-payoff.d.ts.map +1 -0
- package/dist/lesson-payoff.js +597 -0
- package/dist/lesson-payoff.js.map +1 -0
- package/dist/loop-blobs.generated.js +2 -2
- package/dist/loop-blobs.generated.js.map +1 -1
- package/dist/mutation-gate.d.ts +31 -8
- package/dist/mutation-gate.d.ts.map +1 -1
- package/dist/mutation-gate.js +57 -16
- package/dist/mutation-gate.js.map +1 -1
- package/dist/named-lock.d.ts.map +1 -1
- package/dist/named-lock.js +11 -9
- package/dist/named-lock.js.map +1 -1
- package/dist/native-dep-probe.d.ts +11 -0
- package/dist/native-dep-probe.d.ts.map +1 -0
- package/dist/native-dep-probe.js +100 -0
- package/dist/native-dep-probe.js.map +1 -0
- package/dist/operations.d.ts.map +1 -1
- package/dist/operations.js +82 -1
- package/dist/operations.js.map +1 -1
- package/dist/parser-safe-region.d.ts +47 -0
- package/dist/parser-safe-region.d.ts.map +1 -0
- package/dist/parser-safe-region.js +47 -0
- package/dist/parser-safe-region.js.map +1 -0
- package/dist/patterns.d.ts +21 -0
- package/dist/patterns.d.ts.map +1 -1
- package/dist/patterns.js +52 -4
- package/dist/patterns.js.map +1 -1
- package/dist/profile.d.ts +202 -0
- package/dist/profile.d.ts.map +1 -0
- package/dist/profile.js +536 -0
- package/dist/profile.js.map +1 -0
- package/dist/project-skills-root.d.ts +44 -0
- package/dist/project-skills-root.d.ts.map +1 -0
- package/dist/project-skills-root.js +62 -0
- package/dist/project-skills-root.js.map +1 -0
- package/dist/publish.d.ts +5 -3
- package/dist/publish.d.ts.map +1 -1
- package/dist/publish.js +46 -8
- package/dist/publish.js.map +1 -1
- package/dist/qe-rounds.d.ts +75 -0
- package/dist/qe-rounds.d.ts.map +1 -0
- package/dist/qe-rounds.js +174 -0
- package/dist/qe-rounds.js.map +1 -0
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +5 -1
- package/dist/registry.js.map +1 -1
- package/dist/run-records.d.ts.map +1 -1
- package/dist/run-records.js +8 -1
- package/dist/run-records.js.map +1 -1
- package/dist/setup.d.ts +35 -4
- package/dist/setup.d.ts.map +1 -1
- package/dist/setup.js +86 -23
- package/dist/setup.js.map +1 -1
- package/dist/sign.d.ts +29 -24
- package/dist/sign.d.ts.map +1 -1
- package/dist/sign.js +183 -61
- package/dist/sign.js.map +1 -1
- package/dist/store-location.d.ts +56 -0
- package/dist/store-location.d.ts.map +1 -0
- package/dist/store-location.js +56 -0
- package/dist/store-location.js.map +1 -0
- package/dist/store-lock.d.ts +1 -0
- package/dist/store-lock.d.ts.map +1 -1
- package/dist/store-lock.js +7 -1
- package/dist/store-lock.js.map +1 -1
- package/dist/store-merge.d.ts +55 -0
- package/dist/store-merge.d.ts.map +1 -0
- package/dist/store-merge.js +77 -0
- package/dist/store-merge.js.map +1 -0
- package/dist/teach-target.d.ts +61 -0
- package/dist/teach-target.d.ts.map +1 -0
- package/dist/teach-target.js +105 -0
- package/dist/teach-target.js.map +1 -0
- package/dist/vector-tier.d.ts +30 -0
- package/dist/vector-tier.d.ts.map +1 -1
- package/dist/vector-tier.js +178 -20
- package/dist/vector-tier.js.map +1 -1
- package/package.json +13 -13
- package/sbom.json +591 -87
- package/src/amendment-trace.ts +34 -4
- package/src/book-kb.ts +17 -0
- package/src/feature-adr-checkpoints.ts +111 -2
- package/src/feature-adr-routing.ts +146 -7
- package/src/index.ts +55 -3
- package/src/learning-backend.ts +62 -11
- package/src/lesson-bandit.ts +279 -0
- package/src/lesson-payoff.ts +728 -0
- package/src/loop-blobs.generated.ts +2 -2
- package/src/mutation-gate.ts +74 -17
- package/src/named-lock.ts +10 -8
- package/src/native-dep-probe.ts +118 -0
- package/src/operations.ts +77 -1
- package/src/parser-safe-region.ts +65 -0
- package/src/patterns.ts +76 -6
- package/src/profile.ts +593 -0
- package/src/project-skills-root.ts +63 -0
- package/src/publish.ts +43 -7
- package/src/qe-rounds.ts +226 -0
- package/src/registry.ts +5 -1
- package/src/run-records.ts +9 -1
- package/src/setup.ts +87 -23
- package/src/sign.ts +180 -60
- package/src/store-location.ts +76 -0
- package/src/store-lock.ts +8 -1
- package/src/store-merge.ts +91 -0
- package/src/teach-target.ts +126 -0
- package/src/vector-tier.ts +236 -21
package/src/patterns.ts
CHANGED
|
@@ -31,6 +31,7 @@ import { resolveAgentdbPath } from './agentdb-index.js';
|
|
|
31
31
|
import type { VectorEntry } from './vector-tier.js';
|
|
32
32
|
import { rankLessonsByDelta, type LessonHistory } from './safla-delta.js';
|
|
33
33
|
import { withStoreLock, withStoreLockSync, StoreLockTimeoutError, StoreLockCompromisedError } from './store-lock.js';
|
|
34
|
+
import { describeNativeDep, exerciseSqliteOpen, probeNativeDep } from './native-dep-probe.js';
|
|
34
35
|
|
|
35
36
|
/** A learned pattern as written by `dz teach` to `.dz/patterns.jsonl`. */
|
|
36
37
|
export interface PatternRecord {
|
|
@@ -106,6 +107,24 @@ export interface MemoryLearningConfig {
|
|
|
106
107
|
readonly quarantineDamp: number;
|
|
107
108
|
/** Days after which an unreinforced quarantined lesson is an EXPIRY CANDIDATE (informational). */
|
|
108
109
|
readonly quarantineExpireDays: number;
|
|
110
|
+
/**
|
|
111
|
+
* Bandit payoff re-rank (feature lesson-bandit-rerank, ADR-001). When true, recall adds a BOUNDED
|
|
112
|
+
* term derived from each lesson's measured payoff posterior — "has this lesson ever actually
|
|
113
|
+
* helped", the axis similarity cannot answer. ADDITIVE alongside {@link deltaRerank}, never a
|
|
114
|
+
* replacement, and capped at the same `REINFORCE_RRF_CAP`: similarity still decides WHICH lessons
|
|
115
|
+
* are candidates; the bandit only reorders WITHIN them. Default FALSE: absent config is
|
|
116
|
+
* byte-identical to today — no file read, no file written, no term applied.
|
|
117
|
+
*/
|
|
118
|
+
readonly banditRerank: boolean;
|
|
119
|
+
/**
|
|
120
|
+
* Bandit EXPLORATION (feature lesson-bandit-rerank, ADR-003). When true, an arm with no evidence
|
|
121
|
+
* may receive a bounded trial lift so it can accumulate some. This deliberately weakens the
|
|
122
|
+
* view-does-not-promote posture, so it SHIPS DISARMED and is a separate flag: enabling payoff
|
|
123
|
+
* re-ranking must never silently mean "start surfacing unproven lessons". Quarantined lessons are
|
|
124
|
+
* NEVER explored in any configuration. Default FALSE; `true` with `banditRerank: false` is a
|
|
125
|
+
* warned no-op.
|
|
126
|
+
*/
|
|
127
|
+
readonly banditExploration: boolean;
|
|
109
128
|
}
|
|
110
129
|
|
|
111
130
|
/**
|
|
@@ -141,10 +160,10 @@ export function readLearningConfig(projectRoot: string): LearningConfig {
|
|
|
141
160
|
}
|
|
142
161
|
|
|
143
162
|
export function readMemoryLearningConfig(projectRoot: string): MemoryLearningConfig {
|
|
144
|
-
const fallback: MemoryLearningConfig = { backend: 'native', onRecallHits: true, usesSat: 64, halfLifeDays: 30, reinforceThreshold: 0.95, deltaRerank: false, quarantine: false, quarantineDamp: 0.5, quarantineExpireDays: 30 };
|
|
163
|
+
const fallback: MemoryLearningConfig = { backend: 'native', onRecallHits: true, usesSat: 64, halfLifeDays: 30, reinforceThreshold: 0.95, deltaRerank: false, quarantine: false, quarantineDamp: 0.5, quarantineExpireDays: 30, banditRerank: false, banditExploration: false };
|
|
145
164
|
try {
|
|
146
165
|
const parsed = JSON.parse(readFileSync(join(projectRoot, '.dz', 'config.json'), 'utf-8')) as {
|
|
147
|
-
memory?: { learning?: { backend?: string; onRecallHits?: boolean; usesSat?: number; halfLifeDays?: number; reinforceThreshold?: number; deltaRerank?: boolean; quarantine?: boolean; quarantineDamp?: number; quarantineExpireDays?: number } };
|
|
166
|
+
memory?: { learning?: { backend?: string; onRecallHits?: boolean; usesSat?: number; halfLifeDays?: number; reinforceThreshold?: number; deltaRerank?: boolean; quarantine?: boolean; quarantineDamp?: number; quarantineExpireDays?: number; banditRerank?: boolean; banditExploration?: boolean } };
|
|
148
167
|
};
|
|
149
168
|
const learning = parsed.memory?.learning ?? {};
|
|
150
169
|
const backend = learning.backend === 'off' || learning.backend === 'ruvector-gnn' || learning.backend === 'native' ? learning.backend : 'native';
|
|
@@ -168,6 +187,11 @@ export function readMemoryLearningConfig(projectRoot: string): MemoryLearningCon
|
|
|
168
187
|
typeof learning.quarantineExpireDays === 'number' && Number.isFinite(learning.quarantineExpireDays) && learning.quarantineExpireDays > 0
|
|
169
188
|
? Math.floor(learning.quarantineExpireDays)
|
|
170
189
|
: fallback.quarantineExpireDays,
|
|
190
|
+
// Same `=== true` discipline as deltaRerank/quarantine: absent, null, "true" (a string), 1, or
|
|
191
|
+
// any legacy value ⇒ false. That is what makes "flag absent ⇒ byte-identical" true BY
|
|
192
|
+
// CONSTRUCTION rather than by care (ADR-001 R1).
|
|
193
|
+
banditRerank: learning.banditRerank === true,
|
|
194
|
+
banditExploration: learning.banditExploration === true,
|
|
171
195
|
};
|
|
172
196
|
} catch {
|
|
173
197
|
return fallback;
|
|
@@ -574,16 +598,54 @@ export interface ReinforcePatternResult {
|
|
|
574
598
|
readonly dzId?: string;
|
|
575
599
|
readonly uses?: number;
|
|
576
600
|
readonly error?: string;
|
|
601
|
+
/** The reward value actually observed for this reinforcement, clamped to [0,1]. */
|
|
602
|
+
readonly reward?: number;
|
|
577
603
|
}
|
|
578
604
|
|
|
579
|
-
export async function reinforcePattern(projectRoot: string, dzIdOrText: string, opts: { reward?: number; ts?: string; mergedFrom?: readonly string[]; exposure?: boolean } = {}): Promise<ReinforcePatternResult> {
|
|
605
|
+
export async function reinforcePattern(projectRoot: string, dzIdOrText: string, opts: { reward?: number; ts?: string; mergedFrom?: readonly string[]; exposure?: boolean; domain?: string } = {}): Promise<ReinforcePatternResult> {
|
|
580
606
|
// The WHOLE read-modify-write holds the store lock (finding 5): two concurrent
|
|
581
607
|
// reinforces would otherwise both read uses=N and both write back N+1.
|
|
608
|
+
let result: ReinforcePatternResult;
|
|
582
609
|
try {
|
|
583
|
-
|
|
610
|
+
result = await withStoreLock(projectRoot, async () => reinforcePatternLocked(projectRoot, dzIdOrText, opts));
|
|
584
611
|
} catch (err) {
|
|
585
612
|
return { ok: false, error: lockErrorMessage(err) };
|
|
586
613
|
}
|
|
614
|
+
// ── Bandit reward emission (feature lesson-bandit-rerank, ADR-001 D-5 / architecture §4) ──
|
|
615
|
+
//
|
|
616
|
+
// WHERE: here, in `reinforcePattern`, and NOT inside `reinforcePatternLocked` — that body runs
|
|
617
|
+
// under `withStoreLock`, and the bandit takes a DIFFERENT named lock. Lock nesting is AVOIDED,
|
|
618
|
+
// not managed: the bandit call is made after the store lock is released, from the result the
|
|
619
|
+
// locked section already returns. A crash between the two leaves the bandit one reward behind —
|
|
620
|
+
// a tolerable, self-correcting inconsistency for a ranking hint, and explicitly NOT tolerable for
|
|
621
|
+
// the store itself, which is why the store write is the one inside the lock.
|
|
622
|
+
//
|
|
623
|
+
// WHEN: only on the non-exposure branch — the SAME predicate that decides quarantine promotion
|
|
624
|
+
// eleven lines below. Hanging both on one predicate means the two can never disagree; the
|
|
625
|
+
// exposure≠reward distinction has ONE implementation, not two that must be kept in sync (INV-2).
|
|
626
|
+
//
|
|
627
|
+
// The store write is authoritative; the bandit is a derived index. Its failure is counted inside
|
|
628
|
+
// `recordReward` and can never fail a reinforce.
|
|
629
|
+
if (result.ok && result.dzId !== undefined && opts.exposure !== true) {
|
|
630
|
+
try {
|
|
631
|
+
if (readMemoryLearningConfig(projectRoot).banditRerank) {
|
|
632
|
+
// Dynamic import so the module is not even LOADED on the disarmed path (INV-1), and so
|
|
633
|
+
// patterns.ts keeps no static edge to a module that imports it.
|
|
634
|
+
const payoff = await import('./lesson-payoff.js');
|
|
635
|
+
const ev = payoff.makeRewardEvent(
|
|
636
|
+
result.dzId,
|
|
637
|
+
// HONEST LIMIT: a confirmation carries no memory of WHICH recall surfaced the lesson, so
|
|
638
|
+
// without an explicit `domain` the reward lands in the `general` bucket — the same bucket
|
|
639
|
+
// an undomained recall reads. A caller that knows the recall context should name it.
|
|
640
|
+
payoff.contextKeyFor(opts.domain),
|
|
641
|
+
result.reward ?? 1,
|
|
642
|
+
opts.ts ?? new Date().toISOString(),
|
|
643
|
+
);
|
|
644
|
+
if (ev !== null) payoff.recordReward(projectRoot, ev);
|
|
645
|
+
}
|
|
646
|
+
} catch { /* counted inside the payoff module; a derived index never fails a reinforce */ }
|
|
647
|
+
}
|
|
648
|
+
return result;
|
|
587
649
|
}
|
|
588
650
|
|
|
589
651
|
async function reinforcePatternLocked(projectRoot: string, dzIdOrText: string, opts: { reward?: number; ts?: string; mergedFrom?: readonly string[]; exposure?: boolean }): Promise<ReinforcePatternResult> {
|
|
@@ -619,7 +681,7 @@ async function reinforcePatternLocked(projectRoot: string, dzIdOrText: string, o
|
|
|
619
681
|
try {
|
|
620
682
|
appendFileSync(join(projectRoot, '.dz', 'sessions.jsonl'), JSON.stringify({ event: 'reinforce', ts, dzId: rec.id, uses: nextState.uses }) + '\n');
|
|
621
683
|
} catch { /* best-effort */ }
|
|
622
|
-
return { ok: true, dzId: rec.id, uses: nextState.uses };
|
|
684
|
+
return { ok: true, dzId: rec.id, uses: nextState.uses, reward: observed };
|
|
623
685
|
}
|
|
624
686
|
|
|
625
687
|
export async function updateReinforcementState(projectRoot: string, dzId: string, state: ReinforcementState): Promise<ReinforcePatternResult> {
|
|
@@ -1211,7 +1273,11 @@ function countNoiseVectors(projectRoot: string): { removed: number; error?: stri
|
|
|
1211
1273
|
db.close();
|
|
1212
1274
|
}
|
|
1213
1275
|
} catch (err) {
|
|
1214
|
-
|
|
1276
|
+
const verdict = probeNativeDep(projectRoot, 'better-sqlite3', exerciseSqliteOpen, 'sqlite-open');
|
|
1277
|
+
const message = verdict.state === 'unusable'
|
|
1278
|
+
? describeNativeDep(verdict)
|
|
1279
|
+
: err instanceof Error ? err.message : String(err);
|
|
1280
|
+
return { removed: 0, error: `vector mirror: ${message}` };
|
|
1215
1281
|
}
|
|
1216
1282
|
}
|
|
1217
1283
|
|
|
@@ -1253,6 +1319,10 @@ function pruneNoiseVectors(projectRoot: string): { removed: number; error?: stri
|
|
|
1253
1319
|
db.close();
|
|
1254
1320
|
}
|
|
1255
1321
|
} catch (err) {
|
|
1322
|
+
const verdict = probeNativeDep(projectRoot, 'better-sqlite3', exerciseSqliteOpen, 'sqlite-open');
|
|
1323
|
+
if (verdict.state === 'unusable') {
|
|
1324
|
+
return { removed: 0, error: `vector mirror: ${describeNativeDep(verdict)}` };
|
|
1325
|
+
}
|
|
1256
1326
|
return { removed: 0, error: `vector prune failed: ${err instanceof Error ? err.message : String(err)}` };
|
|
1257
1327
|
}
|
|
1258
1328
|
}
|