@dzhechkov/harness-core 0.7.2 → 0.7.4
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 +121 -41
- package/README.md +1 -1
- package/dist/cli-flag-notice.d.ts +50 -0
- package/dist/cli-flag-notice.d.ts.map +1 -0
- package/dist/cli-flag-notice.js +106 -0
- package/dist/cli-flag-notice.js.map +1 -0
- package/dist/event-chain.d.ts +50 -0
- package/dist/event-chain.d.ts.map +1 -1
- package/dist/event-chain.js +31 -0
- package/dist/event-chain.js.map +1 -1
- package/dist/index.d.ts +9 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -3
- package/dist/index.js.map +1 -1
- package/dist/name-check.d.ts +98 -0
- package/dist/name-check.d.ts.map +1 -0
- package/dist/name-check.js +333 -0
- package/dist/name-check.js.map +1 -0
- package/dist/operations.d.ts.map +1 -1
- package/dist/operations.js +33 -5
- package/dist/operations.js.map +1 -1
- package/dist/provenance.d.ts +100 -92
- package/dist/provenance.d.ts.map +1 -1
- package/dist/provenance.js +122 -122
- package/dist/provenance.js.map +1 -1
- package/dist/recall-domain-boost.d.ts +10 -3
- package/dist/recall-domain-boost.d.ts.map +1 -1
- package/dist/recall-domain-boost.js +7 -0
- package/dist/recall-domain-boost.js.map +1 -1
- package/dist/recall-hook-policy.d.ts +15 -0
- package/dist/recall-hook-policy.d.ts.map +1 -1
- package/dist/recall-hook-policy.js +59 -0
- package/dist/recall-hook-policy.js.map +1 -1
- package/dist/recap.d.ts +146 -0
- package/dist/recap.d.ts.map +1 -0
- package/dist/recap.js +346 -0
- package/dist/recap.js.map +1 -0
- package/dist/retro.d.ts +131 -0
- package/dist/retro.d.ts.map +1 -0
- package/dist/retro.js +207 -0
- package/dist/retro.js.map +1 -0
- package/dist/score.d.ts +21 -0
- package/dist/score.d.ts.map +1 -1
- package/dist/score.js +44 -3
- package/dist/score.js.map +1 -1
- package/dist/vector-tier.d.ts +54 -0
- package/dist/vector-tier.d.ts.map +1 -1
- package/dist/vector-tier.js +69 -8
- package/dist/vector-tier.js.map +1 -1
- package/package.json +8 -8
- package/sbom.json +240 -40
- package/src/cli-flag-notice.ts +114 -0
- package/src/event-chain.ts +64 -0
- package/src/index.ts +13 -0
- package/src/name-check.ts +331 -0
- package/src/operations.ts +34 -6
- package/src/provenance.ts +217 -0
- package/src/recall-domain-boost.ts +10 -3
- package/src/recall-hook-policy.ts +60 -0
- package/src/recap.ts +462 -0
- package/src/score.ts +53 -3
- package/src/vector-tier.ts +109 -10
package/src/vector-tier.ts
CHANGED
|
@@ -133,8 +133,21 @@ export interface ImportVectorRow {
|
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
/** The engine PORT — both adapters implement exactly this surface (04 §4.1). */
|
|
136
|
+
/**
|
|
137
|
+
* Is this engine's `similarity` a real cosine, or only good enough to RANK by?
|
|
138
|
+
*
|
|
139
|
+
* `agentdb` computes a magnitude-normalised cosine over the stored vectors, so its number is
|
|
140
|
+
* comparable and lives in the space the recall floors were calibrated in. The `rvf` adapter returns
|
|
141
|
+
* `-distance` — unbounded, and the metric is not established — so its number may only order rows.
|
|
142
|
+
* Printing it beside a 0.38 cosine floor would hand the reader a figure that looks calibrated and is
|
|
143
|
+
* not; that is the one lie this feature must not tell (ADR, features/recall-true-closeness).
|
|
144
|
+
*/
|
|
145
|
+
export type SimilarityKind = 'cosine' | 'rank-only';
|
|
146
|
+
|
|
136
147
|
export interface VectorEngine {
|
|
137
148
|
readonly kind: VectorEngineKind;
|
|
149
|
+
/** Absent means `rank-only`: an engine must SAY its number is a cosine to have it shown as one. */
|
|
150
|
+
readonly similarityKind?: SimilarityKind;
|
|
138
151
|
upsert(entries: readonly VectorEntry[]): Promise<{ indexed: number; error?: string | undefined }>;
|
|
139
152
|
search(query: string, limit: number): Promise<{ hits: VectorHit[]; error?: string | undefined }>;
|
|
140
153
|
listIds(): Promise<{ ids: string[]; error?: string | undefined }>;
|
|
@@ -173,6 +186,14 @@ export interface HybridHit {
|
|
|
173
186
|
readonly score: number;
|
|
174
187
|
/** lesson-quarantine: set only for a quarantined hit — display marks ⚠q, ranking was damped. */
|
|
175
188
|
readonly quarantined?: boolean;
|
|
189
|
+
/**
|
|
190
|
+
* Raw closeness from the semantic leg, when the engine reports a genuine cosine. ABSENT for a
|
|
191
|
+
* lexical-only hit and for an engine whose score is not a cosine — the honest display there is a
|
|
192
|
+
* dash, never a substitute number. On a `both` hit this is the SEMANTIC leg's cosine, which
|
|
193
|
+
* explains less of the ordering than it may appear to: the list is ranked by RRF plus learning
|
|
194
|
+
* signals, not by this.
|
|
195
|
+
*/
|
|
196
|
+
readonly similarity?: number;
|
|
176
197
|
}
|
|
177
198
|
|
|
178
199
|
/** Outcome of {@link recallHybrid}. With no engine this is content-identical to `recallPatterns`. */
|
|
@@ -243,6 +264,8 @@ export interface VectorTierStatus {
|
|
|
243
264
|
* project print a fully-healthy status line over a dead writer (ADR-001).
|
|
244
265
|
*/
|
|
245
266
|
readonly mirrorWriterEnabled: boolean;
|
|
267
|
+
/** WHY it is on or off — so the surface printing it cannot invent a cause (see mirrorWriterReason). */
|
|
268
|
+
readonly mirrorWriterState: MirrorWriterState;
|
|
246
269
|
/**
|
|
247
270
|
* Vectors of OTHER dz-owned task types (today: `dz-backlog`). Reported separately so a store of N
|
|
248
271
|
* vectors can be fully accounted for, and never folded into `mirrored`, which must stay comparable
|
|
@@ -521,15 +544,63 @@ export function readHarmonizeThreshold(projectRoot: string): number {
|
|
|
521
544
|
* `false`, so its `dz teach` output stays byte-identical to the pre-feature baseline (AC-1).
|
|
522
545
|
*/
|
|
523
546
|
export function vectorMirrorEnabled(projectRoot: string): boolean {
|
|
547
|
+
return mirrorWriterReason(projectRoot).enabled;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
/** Why the mirror writer is on or off — a CLOSED set, so a caller cannot invent a cause. */
|
|
551
|
+
export type MirrorWriterState =
|
|
552
|
+
| 'on'
|
|
553
|
+
/** No `.dz/config.json` at all — an unconfigured project, which is the normal quiet case. */
|
|
554
|
+
| 'no-config'
|
|
555
|
+
/** The config exists but could not be read or parsed. */
|
|
556
|
+
| 'config-unreadable'
|
|
557
|
+
/** The config is readable and simply does not enable a mirror. */
|
|
558
|
+
| 'not-enabled'
|
|
559
|
+
/** The config explicitly turns the vector tier off. */
|
|
560
|
+
| 'engine-off';
|
|
561
|
+
|
|
562
|
+
/**
|
|
563
|
+
* The mirror writer's state AND its real cause.
|
|
564
|
+
*
|
|
565
|
+
* Every failure used to collapse into `false`, and the one message printed above it named ONE
|
|
566
|
+
* specific cause: "no memory.backend=agentdb". MEASURED 2026-08-24 with a config that sets
|
|
567
|
+
* `memory.vector.engine: "off"` — the status line correctly said OFF and then blamed a setting the
|
|
568
|
+
* config did not mention. A diagnosis that names the wrong cause sends the reader to fix something
|
|
569
|
+
* that is not broken, which is worse than saying nothing.
|
|
570
|
+
*/
|
|
571
|
+
export function mirrorWriterReason(projectRoot: string): { enabled: boolean; state: MirrorWriterState } {
|
|
572
|
+
const path = join(projectRoot, '.dz', 'config.json');
|
|
573
|
+
if (!existsSync(path)) return { enabled: false, state: 'no-config' };
|
|
574
|
+
let cfg: { memory?: { backend?: string; vector?: { engine?: string } } };
|
|
524
575
|
try {
|
|
525
|
-
|
|
526
|
-
memory?: { backend?: string; vector?: { engine?: string } };
|
|
527
|
-
};
|
|
528
|
-
if (cfg.memory?.backend === 'agentdb') return true;
|
|
529
|
-
const engine = cfg.memory?.vector?.engine;
|
|
530
|
-
return engine === 'agentdb' || engine === 'rvf';
|
|
576
|
+
cfg = JSON.parse(readFileSync(path, 'utf-8')) as typeof cfg;
|
|
531
577
|
} catch {
|
|
532
|
-
return false;
|
|
578
|
+
return { enabled: false, state: 'config-unreadable' };
|
|
579
|
+
}
|
|
580
|
+
const engine = cfg.memory?.vector?.engine;
|
|
581
|
+
// An explicit `off` WINS over `memory.backend`, because that is what the engine resolution itself
|
|
582
|
+
// does. With `{"memory":{"backend":"agentdb","vector":{"engine":"off"}}}` the same status output
|
|
583
|
+
// printed `Engine: none — vector tier disabled` and `Mirror writer: ON` one line apart
|
|
584
|
+
// (cross-family review, codex `gpt-5.6-sol`, 2026-08-24). A report that contradicts itself inside
|
|
585
|
+
// one screen is worse than either half alone, and the half that was wrong is this one: nothing can
|
|
586
|
+
// queue to a tier that is off.
|
|
587
|
+
if (engine === 'off') return { enabled: false, state: 'engine-off' };
|
|
588
|
+
if (cfg.memory?.backend === 'agentdb') return { enabled: true, state: 'on' };
|
|
589
|
+
if (engine === 'agentdb' || engine === 'rvf') return { enabled: true, state: 'on' };
|
|
590
|
+
return { enabled: false, state: 'not-enabled' };
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
/** The sentence a reader can act on, for each state. */
|
|
594
|
+
export function mirrorWriterExplanation(state: MirrorWriterState): string {
|
|
595
|
+
switch (state) {
|
|
596
|
+
case 'on': return 'teach is queueing to the mirror';
|
|
597
|
+
// "has never configured" is a claim about HISTORY from an observation about the PRESENT: the
|
|
598
|
+
// file may be tracked in git and merely deleted from the working tree (cross-family review,
|
|
599
|
+
// codex gpt-5.6-sol, 2026-08-24). Absence proves only absence.
|
|
600
|
+
case 'no-config': return 'no .dz/config.json here — memory is not configured in this working tree, and nothing is queueing';
|
|
601
|
+
case 'config-unreadable': return '.dz/config.json exists but could not be read or parsed — fix the file, not the settings';
|
|
602
|
+
case 'engine-off': return '.dz/config.json sets memory.vector.engine = "off" — the tier is deliberately disabled';
|
|
603
|
+
case 'not-enabled': return '.dz/config.json enables no mirror (needs memory.backend=agentdb, or memory.vector.engine=agentdb|rvf) — teach is NOT queueing';
|
|
533
604
|
}
|
|
534
605
|
}
|
|
535
606
|
|
|
@@ -806,6 +877,13 @@ export interface RankedPattern {
|
|
|
806
877
|
readonly id: string;
|
|
807
878
|
readonly pattern: PatternRecord;
|
|
808
879
|
readonly backend: RecallHit['backend'];
|
|
880
|
+
/**
|
|
881
|
+
* The semantic leg's raw closeness, when the engine reports a real cosine. Rides ALONGSIDE the RRF
|
|
882
|
+
* score and never enters the ranking maths — four things depend on RRF magnitude (the reinforce
|
|
883
|
+
* cap, quarantine damping, the learning uplift, and an ADR-level note in backlog.ts), so this is a
|
|
884
|
+
* sibling field, never a repurposing.
|
|
885
|
+
*/
|
|
886
|
+
readonly similarity?: number;
|
|
809
887
|
}
|
|
810
888
|
|
|
811
889
|
const RRF_K = 60;
|
|
@@ -827,7 +905,7 @@ export function mergeHybridHits(
|
|
|
827
905
|
opts: { readonly limit: number; readonly semanticWeight?: number | undefined },
|
|
828
906
|
): HybridHit[] {
|
|
829
907
|
const weight = opts.semanticWeight ?? 1;
|
|
830
|
-
interface Acc { pattern: PatternRecord; lex?: RecallHit['backend']; sem: boolean; score: number }
|
|
908
|
+
interface Acc { pattern: PatternRecord; lex?: RecallHit['backend']; sem: boolean; score: number; similarity?: number }
|
|
831
909
|
const acc = new Map<string, Acc>();
|
|
832
910
|
lexical.forEach((h, rank) => {
|
|
833
911
|
const cur = acc.get(h.id) ?? { pattern: h.pattern, sem: false, score: 0 };
|
|
@@ -839,6 +917,10 @@ export function mergeHybridHits(
|
|
|
839
917
|
const cur = acc.get(h.id) ?? { pattern: h.pattern, sem: false, score: 0 };
|
|
840
918
|
cur.sem = true;
|
|
841
919
|
cur.score += weight / (RRF_K + rank + 1);
|
|
920
|
+
// The cosine rides along untouched by the ranking maths. On a hit both legs found, this is the
|
|
921
|
+
// SEMANTIC leg's number — stated in the field's own doc, because it explains less of the order
|
|
922
|
+
// than it looks like it does.
|
|
923
|
+
if (h.similarity !== undefined) cur.similarity = h.similarity;
|
|
842
924
|
acc.set(h.id, cur);
|
|
843
925
|
});
|
|
844
926
|
// Ties break by EVIDENCE, not by the id alphabet: a hit both legs found outranks one only a single
|
|
@@ -853,6 +935,7 @@ export function mergeHybridHits(
|
|
|
853
935
|
pattern: v.pattern,
|
|
854
936
|
backend: v.lex !== undefined && v.sem ? ('both' as const) : v.lex ?? ('vector' as const),
|
|
855
937
|
score: v.score,
|
|
938
|
+
...(v.similarity === undefined ? {} : { similarity: v.similarity }),
|
|
856
939
|
});
|
|
857
940
|
// `slice(0, -1)` drops the LAST element instead of returning nothing, so a negative limit used to
|
|
858
941
|
// return almost the whole list (MEASURED: limit -1 over 5 candidates returned 4). `dz recall`
|
|
@@ -1016,6 +1099,8 @@ export async function recallHybrid(
|
|
|
1016
1099
|
const p = recordToPattern(r);
|
|
1017
1100
|
idToPattern.set(r.id, p);
|
|
1018
1101
|
}
|
|
1102
|
+
// Only a declared cosine is allowed to travel as one (ADR: per-engine honesty gate).
|
|
1103
|
+
const cosineEngine = engine.similarityKind === 'cosine';
|
|
1019
1104
|
const semantic: RankedPattern[] = [];
|
|
1020
1105
|
const seen = new Set<string>();
|
|
1021
1106
|
for (const h of sr.hits) {
|
|
@@ -1023,7 +1108,13 @@ export async function recallHybrid(
|
|
|
1023
1108
|
const p = idToPattern.get(h.dzId);
|
|
1024
1109
|
if (p === undefined) continue; // vector-only orphan — the store pruned/expired it; NEVER resurrect
|
|
1025
1110
|
seen.add(h.dzId);
|
|
1026
|
-
|
|
1111
|
+
// The cosine was computed by the engine and then thrown away here — `h.similarity` was read
|
|
1112
|
+
// nowhere in this function, and `relevance` in `--json` has been the RRF rank surrogate ever
|
|
1113
|
+
// since (MEASURED: a nonsense query and a meaningful one both score 1/61 at the top). It now
|
|
1114
|
+
// travels with the hit. Only a genuine cosine travels: an engine whose score is a negated
|
|
1115
|
+
// distance reports `similarityKind: 'rank-only'` and contributes nothing here.
|
|
1116
|
+
semantic.push({ id: h.dzId, pattern: p, backend: 'vector',
|
|
1117
|
+
...(cosineEngine && Number.isFinite(h.similarity) ? { similarity: h.similarity } : {}) });
|
|
1027
1118
|
}
|
|
1028
1119
|
const lex: RankedPattern[] = lexical.map((h) => ({
|
|
1029
1120
|
id: identityToId.get(patternIdentityOf(h.pattern)) ?? patternRecordId(h.pattern),
|
|
@@ -1085,7 +1176,8 @@ export async function vectorTierStatus(
|
|
|
1085
1176
|
const lexicalMirrorable = mirrorableRecords.length;
|
|
1086
1177
|
const pendingEntries = readVectorPending(projectRoot);
|
|
1087
1178
|
const pending = pendingEntries.length;
|
|
1088
|
-
const
|
|
1179
|
+
const mirror = mirrorWriterReason(projectRoot);
|
|
1180
|
+
const mirrorWriterEnabled = mirror.enabled;
|
|
1089
1181
|
const resolved = pickEngine(projectRoot, opts);
|
|
1090
1182
|
if (resolved.engine === undefined) {
|
|
1091
1183
|
// No engine to ask ⇒ the debt is UNKNOWN. Reporting 0 here is precisely the defect this feature
|
|
@@ -1099,6 +1191,7 @@ export async function vectorTierStatus(
|
|
|
1099
1191
|
lexicalMirrorable,
|
|
1100
1192
|
pending,
|
|
1101
1193
|
mirrorWriterEnabled,
|
|
1194
|
+
mirrorWriterState: mirror.state,
|
|
1102
1195
|
};
|
|
1103
1196
|
}
|
|
1104
1197
|
const engine = resolved.engine;
|
|
@@ -1157,6 +1250,7 @@ export async function vectorTierStatus(
|
|
|
1157
1250
|
mirrored,
|
|
1158
1251
|
pending,
|
|
1159
1252
|
mirrorWriterEnabled,
|
|
1253
|
+
mirrorWriterState: mirror.state,
|
|
1160
1254
|
...(unmirrored !== undefined ? { unmirrored } : {}),
|
|
1161
1255
|
...(mirroredOther !== undefined ? { mirroredOther } : {}),
|
|
1162
1256
|
...(orphaned !== undefined ? { orphaned } : {}),
|
|
@@ -1613,6 +1707,9 @@ export async function importRvfCheckpoint(projectRoot: string, source: string, o
|
|
|
1613
1707
|
function agentdbVectorEngine(projectRoot: string): VectorEngine {
|
|
1614
1708
|
return {
|
|
1615
1709
|
kind: 'agentdb',
|
|
1710
|
+
// A magnitude-normalising cosine over the stored vectors — comparable, and in the same space the
|
|
1711
|
+
// recall floors were calibrated in.
|
|
1712
|
+
similarityKind: 'cosine',
|
|
1616
1713
|
async upsert(entries) {
|
|
1617
1714
|
const r = await indexPatternsToAgentdb(
|
|
1618
1715
|
projectRoot,
|
|
@@ -1775,6 +1872,8 @@ function rvfVectorEngine(projectRoot: string): VectorEngine {
|
|
|
1775
1872
|
const noEmbedder = 'rvf engine present but no embedder — install agentdb (dz setup --memory agentdb)';
|
|
1776
1873
|
return {
|
|
1777
1874
|
kind: 'rvf',
|
|
1875
|
+
// `-distance`, unbounded, metric not established: good for ORDER, never for a threshold.
|
|
1876
|
+
similarityKind: 'rank-only',
|
|
1778
1877
|
async upsert(entries) {
|
|
1779
1878
|
const idmap = readRvfIdmap(projectRoot);
|
|
1780
1879
|
const guard = guardRvfEmbedSpace(projectRoot, idmap);
|