@gamaze/hicortex 0.23.1 → 0.24.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 +64 -13
- package/dist/calibration.d.ts +31 -0
- package/dist/calibration.js +38 -1
- package/dist/capture.d.ts +7 -0
- package/dist/capture.js +10 -1
- package/dist/dashboard.d.ts +32 -7
- package/dist/dashboard.js +50 -10
- package/dist/db.js +45 -0
- package/dist/dedup.js +2 -2
- package/dist/distill-queue.d.ts +203 -0
- package/dist/distill-queue.js +440 -0
- package/dist/health.d.ts +13 -1
- package/dist/health.js +6 -1
- package/dist/hosted-boot.d.ts +1 -1
- package/dist/index.js +17 -2
- package/dist/learnings-identity.js +20 -1
- package/dist/localhost-bypass.js +1 -1
- package/dist/mcp-server.js +92 -7
- package/dist/nightly.js +88 -1
- package/dist/nofit.d.ts +1 -1
- package/dist/nofit.js +1 -1
- package/dist/schema-prototypes.d.ts +1 -1
- package/dist/schema-prototypes.js +1 -1
- package/dist/status.d.ts +11 -0
- package/dist/status.js +25 -0
- package/dist/types.d.ts +20 -0
- package/hermes-plugin/hicortex/README.md +13 -6
- package/hermes-plugin/hicortex/__init__.py +7 -0
- package/hermes-plugin/hicortex/client.py +64 -2
- package/hermes-plugin/hicortex/plugin.yaml +1 -1
- package/hermes-plugin/hicortex/provider.py +24 -1
- package/opencode-plugin/hicortex/index.ts +24 -1
- package/package.json +2 -1
- package/pi-extension/hicortex/index.ts +24 -1
- package/server.json +2 -2
- package/dist/eval/decay-eval.d.ts +0 -111
- package/dist/eval/decay-eval.js +0 -214
- package/dist/eval/dups.d.ts +0 -100
- package/dist/eval/dups.js +0 -174
- package/dist/eval/eval-clock.d.ts +0 -32
- package/dist/eval/eval-clock.js +0 -47
- package/dist/eval/eval-db.d.ts +0 -25
- package/dist/eval/eval-db.js +0 -67
- package/dist/eval/graph-eval.d.ts +0 -89
- package/dist/eval/graph-eval.js +0 -246
- package/dist/eval/importance-eval.d.ts +0 -85
- package/dist/eval/importance-eval.js +0 -286
- package/dist/eval/planted-eval.d.ts +0 -30
- package/dist/eval/planted-eval.js +0 -122
- package/dist/eval/planted-fixtures.d.ts +0 -107
- package/dist/eval/planted-fixtures.js +0 -283
- package/dist/eval/planted-harness.d.ts +0 -183
- package/dist/eval/planted-harness.js +0 -651
- package/dist/eval/ranking-battery.d.ts +0 -125
- package/dist/eval/ranking-battery.js +0 -289
- package/dist/eval/ranking-eval.d.ts +0 -61
- package/dist/eval/ranking-eval.js +0 -554
- package/dist/eval/ranking-fixtures.d.ts +0 -117
- package/dist/eval/ranking-fixtures.js +0 -485
- package/dist/eval/recall-sweep.d.ts +0 -87
- package/dist/eval/recall-sweep.js +0 -1030
- package/dist/eval/reflection-census.d.ts +0 -19
- package/dist/eval/reflection-census.js +0 -25
- package/dist/eval/relevance-eval.d.ts +0 -178
- package/dist/eval/relevance-eval.js +0 -2240
- package/dist/eval/run-eval.d.ts +0 -20
- package/dist/eval/run-eval.js +0 -299
package/dist/eval/run-eval.d.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* #191 mechanical audit baseline — orchestrates every section (D1 duplicate
|
|
4
|
-
* rate, D4 decay/prune/no-fit + #192 adoption, D6 link-graph health, the
|
|
5
|
-
* reflection census) into one markdown report.
|
|
6
|
-
*
|
|
7
|
-
* Read-only end to end: opens the snapshot via eval-db.ts (`openSnapshot`,
|
|
8
|
-
* never `initDb()`), never writes to the DB. Not wired into `cli.ts` — this
|
|
9
|
-
* is an internal measurement tool, run via the `eval` npm script:
|
|
10
|
-
*
|
|
11
|
-
* npm run eval -- <snapshot.db> [report.md] [--now=<ISO>]
|
|
12
|
-
*
|
|
13
|
-
* `--now=<ISO>` (#458) pins the clock the age/decay-derived stats (structural
|
|
14
|
-
* strength, adoption age buckets) measure against, so before/after audits are
|
|
15
|
-
* wall-clock-independent. Default: the live clock; the report header records
|
|
16
|
-
* which clock produced it. `state.json` is expected alongside the snapshot DB
|
|
17
|
-
* (same directory) for the `domainCursor`/`relinkCursor` watermarks. Report
|
|
18
|
-
* path defaults to `eval-report.md` next to the DB.
|
|
19
|
-
*/
|
|
20
|
-
export {};
|
package/dist/eval/run-eval.js
DELETED
|
@@ -1,299 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
"use strict";
|
|
3
|
-
/**
|
|
4
|
-
* #191 mechanical audit baseline — orchestrates every section (D1 duplicate
|
|
5
|
-
* rate, D4 decay/prune/no-fit + #192 adoption, D6 link-graph health, the
|
|
6
|
-
* reflection census) into one markdown report.
|
|
7
|
-
*
|
|
8
|
-
* Read-only end to end: opens the snapshot via eval-db.ts (`openSnapshot`,
|
|
9
|
-
* never `initDb()`), never writes to the DB. Not wired into `cli.ts` — this
|
|
10
|
-
* is an internal measurement tool, run via the `eval` npm script:
|
|
11
|
-
*
|
|
12
|
-
* npm run eval -- <snapshot.db> [report.md] [--now=<ISO>]
|
|
13
|
-
*
|
|
14
|
-
* `--now=<ISO>` (#458) pins the clock the age/decay-derived stats (structural
|
|
15
|
-
* strength, adoption age buckets) measure against, so before/after audits are
|
|
16
|
-
* wall-clock-independent. Default: the live clock; the report header records
|
|
17
|
-
* which clock produced it. `state.json` is expected alongside the snapshot DB
|
|
18
|
-
* (same directory) for the `domainCursor`/`relinkCursor` watermarks. Report
|
|
19
|
-
* path defaults to `eval-report.md` next to the DB.
|
|
20
|
-
*/
|
|
21
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
-
const node_path_1 = require("node:path");
|
|
23
|
-
const node_fs_1 = require("node:fs");
|
|
24
|
-
const eval_db_js_1 = require("./eval-db.js");
|
|
25
|
-
const eval_clock_js_1 = require("./eval-clock.js");
|
|
26
|
-
const dups_js_1 = require("./dups.js");
|
|
27
|
-
const decay_eval_js_1 = require("./decay-eval.js");
|
|
28
|
-
const graph_eval_js_1 = require("./graph-eval.js");
|
|
29
|
-
const reflection_census_js_1 = require("./reflection-census.js");
|
|
30
|
-
const retrieval_js_1 = require("../retrieval.js");
|
|
31
|
-
// ---------------------------------------------------------------------------
|
|
32
|
-
// Formatting helpers
|
|
33
|
-
// ---------------------------------------------------------------------------
|
|
34
|
-
function pct(n) {
|
|
35
|
-
return `${(n * 100).toFixed(1)}%`;
|
|
36
|
-
}
|
|
37
|
-
function round(n, places = 4) {
|
|
38
|
-
const f = 10 ** places;
|
|
39
|
-
return Math.round(n * f) / f;
|
|
40
|
-
}
|
|
41
|
-
/** Extract the leading number from a bucket label (e.g. "[0.2, 0.3)" -> 0.2) so buckets render in ascending order. */
|
|
42
|
-
function bucketSortKey(label) {
|
|
43
|
-
const match = label.match(/-?\d+(\.\d+)?/);
|
|
44
|
-
return match ? Number(match[0]) : Number.POSITIVE_INFINITY;
|
|
45
|
-
}
|
|
46
|
-
function histTable(h) {
|
|
47
|
-
const entries = Object.entries(h).sort((a, b) => bucketSortKey(a[0]) - bucketSortKey(b[0]));
|
|
48
|
-
if (entries.length === 0)
|
|
49
|
-
return "_(no data)_\n";
|
|
50
|
-
return entries.map(([bucket, count]) => `| ${bucket} | ${count} |`).join("\n") + "\n";
|
|
51
|
-
}
|
|
52
|
-
// ---------------------------------------------------------------------------
|
|
53
|
-
// Report sections
|
|
54
|
-
// ---------------------------------------------------------------------------
|
|
55
|
-
function renderDups(d) {
|
|
56
|
-
const lines = [];
|
|
57
|
-
lines.push("## D1 — Duplicate rate\n");
|
|
58
|
-
lines.push(`Top-${d.knnK} vector KNN per memory (${d.totalMemories} memories), pairs kept at cosine >= 0.90 and clustered per threshold (union-find). "Excess" = rows that would disappear if every cluster merged to one.\n`);
|
|
59
|
-
lines.push("| Threshold | Clusters | Excess (rows) |");
|
|
60
|
-
lines.push("|---|---|---|");
|
|
61
|
-
for (const t of d.thresholds) {
|
|
62
|
-
lines.push(`| ${t.threshold} | ${t.clusterCount} | ${t.excess} |`);
|
|
63
|
-
}
|
|
64
|
-
lines.push("");
|
|
65
|
-
lines.push(`**Pair attribution** (over all ${d.pairAttribution.totalPairs} pairs at/above the lowest threshold, 0.90): ` +
|
|
66
|
-
`${d.pairAttribution.recoveryReingest} recovery/re-ingest-suspect (${pct(d.pairAttribution.totalPairs > 0 ? d.pairAttribution.recoveryReingest / d.pairAttribution.totalPairs : 0)}), ${d.pairAttribution.organic} organic (${pct(d.pairAttribution.totalPairs > 0 ? d.pairAttribution.organic / d.pairAttribution.totalPairs : 0)}).\n`);
|
|
67
|
-
lines.push(`### Top ${d.topClusters.length} clusters (0.90 threshold, largest first)\n`);
|
|
68
|
-
d.topClusters.forEach((cluster, i) => {
|
|
69
|
-
// #206 decision 2: project is the only merge-safety rail (agent rail removed).
|
|
70
|
-
const mismatch = cluster.metadataMismatch;
|
|
71
|
-
const mismatchFlags = [mismatch.projectMismatch ? "project" : null].filter(Boolean);
|
|
72
|
-
lines.push(`**Cluster ${i + 1}** — size ${cluster.size}, attribution: ${cluster.attribution.recoveryReingest} recovery-pair(s) / ${cluster.attribution.organic} organic-pair(s)` +
|
|
73
|
-
(mismatchFlags.length > 0 ? `, metadata mismatch: ${mismatchFlags.join(", ")}` : ", metadata consistent"));
|
|
74
|
-
for (const m of cluster.members) {
|
|
75
|
-
lines.push(` - \`${m.id.slice(0, 8)}\` ${m.created_at} — ${m.preview.replace(/\n/g, " ")}`);
|
|
76
|
-
}
|
|
77
|
-
lines.push("");
|
|
78
|
-
});
|
|
79
|
-
return lines.join("\n");
|
|
80
|
-
}
|
|
81
|
-
function renderDecay(backlog, prune, structural, adoption) {
|
|
82
|
-
const lines = [];
|
|
83
|
-
lines.push("## D4 — Decay / Prune / No-fit lifecycle + #192 adoption\n");
|
|
84
|
-
lines.push("### Domain classification backlog\n");
|
|
85
|
-
lines.push(`${backlog.nullDomainTotal} memories have NULL domain (of ${backlog.maxRowid} max rowid). Partitioned by ` +
|
|
86
|
-
`\`domainCursor\` (${backlog.domainCursor ?? "unset — classify-domains never run"}), documented in ` +
|
|
87
|
-
`classify-domains.ts as the last fully-committed rowid:\n`);
|
|
88
|
-
lines.push(`- **Never-classified backlog** (rowid > cursor): ${backlog.neverClassifiedBacklog}`);
|
|
89
|
-
lines.push(`- **Classified but no fitting domain** (rowid <= cursor, no-fit path): ${backlog.classifiedButEmpty}\n`);
|
|
90
|
-
lines.push("### Prune dry-run (real production predicate: `stageDecayPrune`, `dryRun: true`)\n");
|
|
91
|
-
lines.push(`Decay clock configured to \`decayHalfLifeDays: ${prune.decayHalfLifeDaysUsed}\` (bedrock has no override — this is the shipped default) before running.\n`);
|
|
92
|
-
lines.push(`- Candidates (would prune today): **${prune.candidates}**`);
|
|
93
|
-
lines.push(`- Pruned: ${prune.pruned} (0 expected — dry run)`);
|
|
94
|
-
lines.push(`- Failed: ${prune.failed}\n`);
|
|
95
|
-
lines.push("### Structural strength — who can EVER prune\n");
|
|
96
|
-
lines.push(`A memory can only ever cross the prune floor (effective strength < 0.01) if its asymptote is below that floor: ` +
|
|
97
|
-
`\`base_strength < sqrt(0.1) ≈ ${round(structural.everPrunableCeiling, 4)}\` (floor = base_strength × importance × 0.1, ` +
|
|
98
|
-
`importance defaults to base_strength).\n`);
|
|
99
|
-
lines.push(`**Ever-prunable: ${structural.everPrunableCount} / ${structural.totalMemories} (${pct(structural.totalMemories > 0 ? structural.everPrunableCount / structural.totalMemories : 0)})** — everyone else has a strength floor that never drops low enough to prune, no matter how long it goes unaccessed.\n`);
|
|
100
|
-
for (const [label, hist] of [
|
|
101
|
-
["Effective strength now", structural.effectiveStrengthNowHistogram],
|
|
102
|
-
["Simulated +180 days (no further access)", structural.effectiveStrengthAt180dHistogram],
|
|
103
|
-
["Simulated +365 days (no further access)", structural.effectiveStrengthAt365dHistogram],
|
|
104
|
-
["Asymptotic floor (never, base_strength² × 0.1)", structural.effectiveStrengthNeverHistogram],
|
|
105
|
-
]) {
|
|
106
|
-
lines.push(`**${label}**\n`);
|
|
107
|
-
lines.push("| Bucket | Count |");
|
|
108
|
-
lines.push("|---|---|");
|
|
109
|
-
lines.push(histTable(hist));
|
|
110
|
-
}
|
|
111
|
-
lines.push("### Adoption (#192 shown_count / access_count)\n");
|
|
112
|
-
lines.push("`shown_count` (migration v8) was deployed ~2 days before this snapshot — near-zero shown counts reflect the " +
|
|
113
|
-
"feature's youth as much as its effectiveness; read this section as a baseline to compare against, not a verdict.\n");
|
|
114
|
-
lines.push(`- Total shown (sum): ${adoption.totalShown}, total access (sum): ${adoption.totalAccess}`);
|
|
115
|
-
lines.push(`- Uses per showing (overall): ${adoption.usesPerShowingOverall !== null ? round(adoption.usesPerShowingOverall) : "n/a (nothing shown yet)"}`);
|
|
116
|
-
lines.push(`- Cold (shown=0 AND access=0): ${adoption.coldShare.coldCount} / ${adoption.coldShare.total} (${pct(adoption.coldShare.share)})\n`);
|
|
117
|
-
lines.push("**shown_count distribution**\n\n| Bucket | Count |\n|---|---|\n" + histTable(adoption.shownCountHistogram));
|
|
118
|
-
lines.push("**access_count distribution**\n\n| Bucket | Count |\n|---|---|\n" + histTable(adoption.accessCountHistogram));
|
|
119
|
-
lines.push("**Uses per showing by source_agent** (agents with at least one showing)\n");
|
|
120
|
-
lines.push("| source_agent | shown | access | ratio |");
|
|
121
|
-
lines.push("|---|---|---|---|");
|
|
122
|
-
const byAgent = Object.entries(adoption.usesPerShowingBySourceAgent)
|
|
123
|
-
.filter(([, v]) => v.shown > 0 || v.access > 0)
|
|
124
|
-
.sort((a, b) => b[1].shown - a[1].shown);
|
|
125
|
-
for (const [agent, v] of byAgent) {
|
|
126
|
-
lines.push(`| ${agent} | ${v.shown} | ${v.access} | ${v.ratio !== null ? round(v.ratio) : "n/a"} |`);
|
|
127
|
-
}
|
|
128
|
-
lines.push("");
|
|
129
|
-
lines.push("**Exposure age profile** — are new memories getting shown?\n");
|
|
130
|
-
lines.push("| Age bucket | Total | Ever shown | Share shown |");
|
|
131
|
-
lines.push("|---|---|---|---|");
|
|
132
|
-
for (const b of adoption.exposureAgeProfile) {
|
|
133
|
-
lines.push(`| ${b.bucket} | ${b.total} | ${b.everShown} | ${pct(b.shareShown)} |`);
|
|
134
|
-
}
|
|
135
|
-
lines.push("");
|
|
136
|
-
return lines.join("\n");
|
|
137
|
-
}
|
|
138
|
-
function renderGraph(g) {
|
|
139
|
-
const lines = [];
|
|
140
|
-
lines.push("## D6 — Link-graph health\n");
|
|
141
|
-
lines.push(`Total links: **${g.totalLinks}**\n`);
|
|
142
|
-
lines.push("| Relationship | Count |");
|
|
143
|
-
lines.push("|---|---|");
|
|
144
|
-
for (const [rel, count] of Object.entries(g.byRelationship)) {
|
|
145
|
-
lines.push(`| ${rel} | ${count} |`);
|
|
146
|
-
}
|
|
147
|
-
lines.push("");
|
|
148
|
-
lines.push(`### Degree distribution (${g.degree.memoriesWithLinks} / ${g.degree.totalMemories} memories have at least one link)\n`);
|
|
149
|
-
lines.push("| Degree bucket | Count |");
|
|
150
|
-
lines.push("|---|---|");
|
|
151
|
-
lines.push(histTable(g.degree.degreeHistogram));
|
|
152
|
-
lines.push(`### Top ${g.degree.topHubs.length} hubs\n`);
|
|
153
|
-
lines.push("| id | degree | project | domain | preview |");
|
|
154
|
-
lines.push("|---|---|---|---|---|");
|
|
155
|
-
for (const h of g.degree.topHubs) {
|
|
156
|
-
lines.push(`| \`${h.id.slice(0, 8)}\` | ${h.degree} | ${h.project ?? "-"} | ${h.domain ?? "-"} | ${h.preview.replace(/\|/g, "/")} |`);
|
|
157
|
-
}
|
|
158
|
-
lines.push("");
|
|
159
|
-
lines.push(`### Cosine drift (stored \`memory_links.strength\` vs recomputed, ${g.drift.sampleSize}-link random sample` +
|
|
160
|
-
(g.drift.skippedMissingEmbedding > 0 ? `, ${g.drift.skippedMissingEmbedding} skipped for missing embeddings` : "") +
|
|
161
|
-
")\n");
|
|
162
|
-
lines.push(`Mean |drift|: ${round(g.drift.meanAbsDrift, 8)}, max |drift|: ${round(g.drift.maxAbsDrift, 8)} ` +
|
|
163
|
-
"(float32 rounding-noise scale (~1e-7) counts as zero drift — strength was set from the same embeddings at link-creation time, so no staleness is expected).\n");
|
|
164
|
-
lines.push("| |drift| bucket | Count |");
|
|
165
|
-
lines.push("|---|---|");
|
|
166
|
-
lines.push(histTable(g.drift.driftHistogram));
|
|
167
|
-
lines.push(`### Dup-noise links (endpoints >= ${g.dupNoise.threshold} cosine, measured over ${g.dupNoise.measured} links with both embeddings)\n`);
|
|
168
|
-
lines.push(`${g.dupNoise.count} / ${g.dupNoise.measured} (${pct(g.dupNoise.share)}) of links connect near-duplicate memories.\n`);
|
|
169
|
-
lines.push(`### Relink migration partition (\`relinkCursor\`: ${g.relinkCursor ?? "unset — relink never run"})\n`);
|
|
170
|
-
lines.push("| Partition | Links | Dup-noise share |");
|
|
171
|
-
lines.push("|---|---|---|");
|
|
172
|
-
lines.push(`| Relinked (source rowid <= cursor) | ${g.relinkedPartition.linkCount} | ${pct(g.relinkedPartition.dupNoiseShare)} |`);
|
|
173
|
-
lines.push(`| Not yet relinked (source rowid > cursor) | ${g.notYetRelinkedPartition.linkCount} | ${pct(g.notYetRelinkedPartition.dupNoiseShare)} |`);
|
|
174
|
-
lines.push("");
|
|
175
|
-
return lines.join("\n");
|
|
176
|
-
}
|
|
177
|
-
function renderReflection(r) {
|
|
178
|
-
const lines = [];
|
|
179
|
-
lines.push("## Reflection census\n");
|
|
180
|
-
lines.push(`Lessons: ${r.totalLessons}, episodes: ${r.totalEpisodes}, yield ratio (lessons/episodes): ${r.yieldRatio !== null ? round(r.yieldRatio) : "n/a"}\n`);
|
|
181
|
-
lines.push("_Not a quality read — actionable-vs-noise sampling is deferred Phase-A grading work._\n");
|
|
182
|
-
if (r.lessonsByDate.length > 0) {
|
|
183
|
-
lines.push("| Date | Lessons |");
|
|
184
|
-
lines.push("|---|---|");
|
|
185
|
-
for (const row of r.lessonsByDate) {
|
|
186
|
-
lines.push(`| ${row.date} | ${row.count} |`);
|
|
187
|
-
}
|
|
188
|
-
lines.push("");
|
|
189
|
-
}
|
|
190
|
-
return lines.join("\n");
|
|
191
|
-
}
|
|
192
|
-
function renderPhaseB(dups, prune, structural, backlog, graph, adoption) {
|
|
193
|
-
const lines = [];
|
|
194
|
-
lines.push("## Phase-B decision inputs\n");
|
|
195
|
-
lines.push("**1. Merge-threshold curve (dup excess at each cosine)**\n");
|
|
196
|
-
for (const t of dups.thresholds) {
|
|
197
|
-
lines.push(`- ${t.threshold}: ${t.clusterCount} clusters, ${t.excess} excess rows`);
|
|
198
|
-
}
|
|
199
|
-
lines.push("");
|
|
200
|
-
lines.push("**2. Prune posture — inert by design or miscalibration?**\n");
|
|
201
|
-
lines.push(`- Dry-run candidates today: ${prune.candidates} (half-life ${prune.decayHalfLifeDaysUsed}d)`);
|
|
202
|
-
lines.push(`- Ever-prunable ceiling: ${structural.everPrunableCount} / ${structural.totalMemories} (${pct(structural.totalMemories > 0 ? structural.everPrunableCount / structural.totalMemories : 0)}) memories can EVER cross the floor regardless of age`);
|
|
203
|
-
lines.push(`- If the current trend holds, compare the now/+180d/+365d histograms above for how many additional memories drift into low-strength bands`);
|
|
204
|
-
lines.push("");
|
|
205
|
-
lines.push("**3. Classification backlog size**\n");
|
|
206
|
-
lines.push(`- ${backlog.neverClassifiedBacklog} never-classified (beyond domainCursor), ${backlog.classifiedButEmpty} classified-but-empty (no-fit), of ${backlog.nullDomainTotal} total NULL-domain`);
|
|
207
|
-
lines.push("");
|
|
208
|
-
lines.push("**4. Link-threshold pile-up evidence**\n");
|
|
209
|
-
lines.push(`- ${graph.dupNoise.count} / ${graph.dupNoise.measured} links (${pct(graph.dupNoise.share)}) connect near-duplicate memories (>= ${graph.dupNoise.threshold} cosine)`);
|
|
210
|
-
lines.push(`- Relinked partition dup-noise share: ${pct(graph.relinkedPartition.dupNoiseShare)} vs not-yet-relinked: ${pct(graph.notYetRelinkedPartition.dupNoiseShare)}`);
|
|
211
|
-
lines.push("");
|
|
212
|
-
lines.push("**5. Adoption snapshot**\n");
|
|
213
|
-
lines.push(`- Cold (never shown, never accessed): ${adoption.coldShare.coldCount} / ${adoption.coldShare.total} (${pct(adoption.coldShare.share)})`);
|
|
214
|
-
lines.push(`- Uses per showing overall: ${adoption.usesPerShowingOverall !== null ? round(adoption.usesPerShowingOverall) : "n/a"} — CAVEAT: shown_count is ~2 days old at snapshot time, read directionally only`);
|
|
215
|
-
lines.push("");
|
|
216
|
-
return lines.join("\n");
|
|
217
|
-
}
|
|
218
|
-
function renderReport(input) {
|
|
219
|
-
const parts = [];
|
|
220
|
-
parts.push("# Hicortex Mechanical Audit Baseline (#191)\n");
|
|
221
|
-
parts.push(`Snapshot: \`${input.dbPath}\` \nGenerated: ${input.generatedAt} \nClock: ${input.clock} (#458 — the instant the age/decay-derived stats measured against) \nRead-only, zero LLM, zero human grading — mechanical measurement only.\n`);
|
|
222
|
-
parts.push(renderDups(input.dups));
|
|
223
|
-
parts.push(renderDecay(input.domainBacklog, input.pruneDryRun, input.structural, input.adoption));
|
|
224
|
-
parts.push(renderGraph(input.graph));
|
|
225
|
-
parts.push(renderReflection(input.reflection));
|
|
226
|
-
parts.push(renderPhaseB(input.dups, input.pruneDryRun, input.structural, input.domainBacklog, input.graph, input.adoption));
|
|
227
|
-
return parts.join("\n");
|
|
228
|
-
}
|
|
229
|
-
// ---------------------------------------------------------------------------
|
|
230
|
-
// CLI entry
|
|
231
|
-
// ---------------------------------------------------------------------------
|
|
232
|
-
function main() {
|
|
233
|
-
// #458: --now=<ISO> pins the age/decay-derived stats' clock; positionals
|
|
234
|
-
// (snapshot, report path) keep working unchanged.
|
|
235
|
-
const positionals = [];
|
|
236
|
-
let nowIso;
|
|
237
|
-
for (const arg of process.argv.slice(2)) {
|
|
238
|
-
const m = arg.match(/^--now=(.+)$/);
|
|
239
|
-
if (m)
|
|
240
|
-
nowIso = m[1];
|
|
241
|
-
else
|
|
242
|
-
positionals.push(arg);
|
|
243
|
-
}
|
|
244
|
-
const [dbPathArg, reportPathArg] = positionals;
|
|
245
|
-
if (!dbPathArg) {
|
|
246
|
-
console.error("Usage: run-eval.js <snapshot.db> [report.md] [--now=<ISO>]");
|
|
247
|
-
process.exitCode = 1;
|
|
248
|
-
return;
|
|
249
|
-
}
|
|
250
|
-
let now;
|
|
251
|
-
try {
|
|
252
|
-
now = (0, eval_clock_js_1.parsePinnedNow)(nowIso);
|
|
253
|
-
}
|
|
254
|
-
catch (err) {
|
|
255
|
-
console.error(`[eval] ${err instanceof Error ? err.message : err}`);
|
|
256
|
-
process.exitCode = 1;
|
|
257
|
-
return;
|
|
258
|
-
}
|
|
259
|
-
console.log(`[eval] clock: ${(0, eval_clock_js_1.clockLabel)(now)}`);
|
|
260
|
-
const nowArg = now ?? new Date(); // the live clock, made explicit for threading
|
|
261
|
-
const dbPath = dbPathArg;
|
|
262
|
-
const stateDir = (0, node_path_1.dirname)(dbPath);
|
|
263
|
-
const reportPath = reportPathArg ?? (0, node_path_1.join)(stateDir, "eval-report.md");
|
|
264
|
-
const db = (0, eval_db_js_1.openSnapshot)(dbPath);
|
|
265
|
-
try {
|
|
266
|
-
console.log("[eval] D1 duplicate audit...");
|
|
267
|
-
const dups = (0, dups_js_1.runDupAudit)(db);
|
|
268
|
-
console.log("[eval] D4 domain backlog...");
|
|
269
|
-
const domainBacklog = (0, decay_eval_js_1.runDomainBacklogAudit)(db, stateDir);
|
|
270
|
-
console.log("[eval] D4 prune dry-run...");
|
|
271
|
-
const pruneDryRun = (0, decay_eval_js_1.runPruneDryRun)(db, retrieval_js_1.DEFAULT_DECAY_HALF_LIFE_DAYS);
|
|
272
|
-
console.log("[eval] D4 structural strength stats...");
|
|
273
|
-
const structural = (0, decay_eval_js_1.runStructuralStrengthStats)(db, nowArg);
|
|
274
|
-
console.log("[eval] D4 adoption stats...");
|
|
275
|
-
const adoption = (0, decay_eval_js_1.runAdoptionStats)(db, nowArg);
|
|
276
|
-
console.log("[eval] D6 link-graph audit...");
|
|
277
|
-
const graph = (0, graph_eval_js_1.runGraphAudit)(db, stateDir);
|
|
278
|
-
console.log("[eval] reflection census...");
|
|
279
|
-
const reflection = (0, reflection_census_js_1.runReflectionCensus)(db);
|
|
280
|
-
const report = renderReport({
|
|
281
|
-
dbPath,
|
|
282
|
-
generatedAt: new Date().toISOString(),
|
|
283
|
-
clock: (0, eval_clock_js_1.clockLabel)(now),
|
|
284
|
-
dups,
|
|
285
|
-
domainBacklog,
|
|
286
|
-
pruneDryRun,
|
|
287
|
-
structural,
|
|
288
|
-
adoption,
|
|
289
|
-
graph,
|
|
290
|
-
reflection,
|
|
291
|
-
});
|
|
292
|
-
(0, node_fs_1.writeFileSync)(reportPath, report, "utf-8");
|
|
293
|
-
console.log(`[eval] report written to ${reportPath}`);
|
|
294
|
-
}
|
|
295
|
-
finally {
|
|
296
|
-
db.close();
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
main();
|