knodin 0.7.4 → 0.7.6
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/README.md +4 -1
- package/dist/bin/cli.js +108 -1859
- package/dist/bin/launcher.js +3 -10
- package/dist/chunks/chunk-DMQAGX77.js +654 -0
- package/dist/chunks/chunk-F4Z3Z766.js +4 -0
- package/dist/chunks/chunk-SIJAQVSX.js +3 -0
- package/dist/chunks/chunk-X6M4HUUE.js +2 -0
- package/dist/chunks/chunk-YPRMY2LP.js +8 -0
- package/dist/chunks/pure-compression-cli-4TA2TQD5.js +5 -0
- package/dist/chunks/server-7EDF4CBY.js +14 -0
- package/dist/chunks/structural-fast-path-KD5KQSPX.js +4 -0
- package/dist/src/init-progress-worker.js +2 -106
- package/dist/src/repair-progress-worker.js +2 -120
- package/docs/INSTALLATION.md +17 -1
- package/docs/releases/0.7.6.md +25 -0
- package/package.json +1 -110
- package/dist/src/agent-integration.js +0 -238
- package/dist/src/artifact-refresh.js +0 -81
- package/dist/src/cli-args.js +0 -274
- package/dist/src/cli-model.js +0 -358
- package/dist/src/codeflow-replay.js +0 -80
- package/dist/src/compact-structural.js +0 -96
- package/dist/src/competitive-cold-mcp.js +0 -40
- package/dist/src/competitive-constraints.js +0 -20
- package/dist/src/competitive-manifest.js +0 -411
- package/dist/src/competitive-measurement.js +0 -183
- package/dist/src/competitive-runner.js +0 -487
- package/dist/src/competitive-sandbox.js +0 -108
- package/dist/src/context-export.js +0 -422
- package/dist/src/context.js +0 -102
- package/dist/src/diagnostics.js +0 -449
- package/dist/src/docs-sections.js +0 -141
- package/dist/src/doctor.js +0 -380
- package/dist/src/engine/ann-hnsw.js +0 -271
- package/dist/src/engine/embeddings.js +0 -193
- package/dist/src/engine/file-walker.js +0 -43
- package/dist/src/engine/git-history.js +0 -289
- package/dist/src/engine/index.js +0 -13377
- package/dist/src/engine/perf.js +0 -115
- package/dist/src/engine/prune.js +0 -112
- package/dist/src/engine/scip-import.js +0 -408
- package/dist/src/engine/source-policy.js +0 -69
- package/dist/src/engine/sqlite.js +0 -71
- package/dist/src/engine/symbol-delete.js +0 -58
- package/dist/src/execution-profile.js +0 -203
- package/dist/src/failure-diagnosis.js +0 -649
- package/dist/src/fleet.js +0 -7
- package/dist/src/git-executable.js +0 -31
- package/dist/src/graph-query-health.js +0 -115
- package/dist/src/hook-manager-integration.js +0 -156
- package/dist/src/index-activity.js +0 -125
- package/dist/src/init-progress.js +0 -155
- package/dist/src/init.js +0 -1254
- package/dist/src/lifecycle-health.js +0 -250
- package/dist/src/lsp-readonly.js +0 -217
- package/dist/src/output-compression.js +0 -629
- package/dist/src/output-telemetry.js +0 -363
- package/dist/src/pr-triage.js +0 -638
- package/dist/src/progressive-evidence.js +0 -473
- package/dist/src/pure-compression-cli.js +0 -101
- package/dist/src/relationship-adapters.js +0 -370
- package/dist/src/release-attestation.js +0 -533
- package/dist/src/release-preflight.js +0 -510
- package/dist/src/repair-progress.js +0 -262
- package/dist/src/repository-init-process.js +0 -173
- package/dist/src/repository-management.js +0 -1231
- package/dist/src/response-budget.js +0 -194
- package/dist/src/server.js +0 -73
- package/dist/src/structural-fast-path.js +0 -338
- package/dist/src/structural-snapshot.js +0 -33
- package/dist/src/system-config.js +0 -615
- package/dist/src/terminal-help.js +0 -83
- package/dist/src/tools/knodin-tools.js +0 -1529
- package/dist/src/update-ceremony.js +0 -158
- package/dist/src/update-policy.js +0 -944
- package/dist/src/update-trust.js +0 -503
- package/dist/src/version.js +0 -13
- package/dist/src/visualization.js +0 -162
- package/dist/src/wait-for-fresh.js +0 -98
- package/dist/src/worktree-lifecycle.js +0 -231
- package/docs/CONTAINED-EXECUTION.md +0 -77
- package/docs/DIAGNOSTICS.md +0 -45
- package/docs/GIT-HISTORY-REVIEW.md +0 -39
- package/docs/PROGRESSIVE-EVIDENCE.md +0 -37
- package/docs/PT-ACCESS-RECOMMENDATION.md +0 -91
- package/docs/RELEASE-0.3-EVIDENCE.md +0 -73
- package/docs/SCIP-IMPORT.md +0 -57
- package/docs/SIGNED-UPDATES.md +0 -151
- package/docs/TELEMETRY.md +0 -46
- package/docs/assets/knodin-favicon.svg +0 -4
- package/docs/releases/0.3.0.md +0 -46
- package/docs/releases/0.4.0.md +0 -68
- package/docs/releases/0.4.1.md +0 -28
- package/docs/releases/0.4.2.md +0 -27
- package/docs/releases/0.4.3.md +0 -23
- package/docs/releases/0.5.0.md +0 -29
- package/docs/releases/0.5.1.md +0 -17
- package/docs/releases/0.6.0.md +0 -18
- package/docs/releases/0.7.0.md +0 -24
- package/docs/releases/0.7.1.md +0 -21
- package/docs/releases/0.7.2.md +0 -21
- package/docs/releases/0.7.3.md +0 -23
- package/docs/releases/0.7.4.md +0 -17
- package/schemas/release-attestation-v1.schema.json +0 -210
|
@@ -1,183 +0,0 @@
|
|
|
1
|
-
import childProcess from "node:child_process";
|
|
2
|
-
import fs from "node:fs";
|
|
3
|
-
/**
|
|
4
|
-
* Twenty warm observations are the minimum that gives nearest-rank p95 a
|
|
5
|
-
* distinct tail observation instead of aliasing a three-sample median.
|
|
6
|
-
*/
|
|
7
|
-
export const MIN_WARM_SAMPLES = 20;
|
|
8
|
-
export const DEFAULT_WARMUP_COUNT = 3;
|
|
9
|
-
export const DEFAULT_COLD_SAMPLES = 5;
|
|
10
|
-
export const DEFAULT_CALL_TIMEOUT_MS = 30_000;
|
|
11
|
-
function percentile(sorted, fraction) {
|
|
12
|
-
const index = Math.max(0, Math.ceil(fraction * sorted.length) - 1);
|
|
13
|
-
return sorted[index];
|
|
14
|
-
}
|
|
15
|
-
export function summarizeLatencySamples(mode, samplesMs, warmupCount) {
|
|
16
|
-
if (!Number.isInteger(warmupCount) || warmupCount < 0)
|
|
17
|
-
throw new Error("Warm-up count must be a non-negative integer");
|
|
18
|
-
if (samplesMs.length === 0)
|
|
19
|
-
throw new Error("At least one latency sample is required");
|
|
20
|
-
if (mode === "warm" && samplesMs.length < MIN_WARM_SAMPLES) {
|
|
21
|
-
throw new Error(`Warm measurements require at least ${MIN_WARM_SAMPLES} samples for a meaningful p95`);
|
|
22
|
-
}
|
|
23
|
-
if (samplesMs.some((sample) => !Number.isFinite(sample) || sample < 0))
|
|
24
|
-
throw new Error("Latency samples must be finite non-negative numbers");
|
|
25
|
-
const raw = [...samplesMs];
|
|
26
|
-
const sorted = [...raw].sort((left, right) => left - right);
|
|
27
|
-
const p50Ms = percentile(sorted, 0.5);
|
|
28
|
-
return {
|
|
29
|
-
mode,
|
|
30
|
-
warmupCount,
|
|
31
|
-
sampleCount: raw.length,
|
|
32
|
-
samplesMs: raw,
|
|
33
|
-
p50Ms,
|
|
34
|
-
p95Ms: percentile(sorted, 0.95),
|
|
35
|
-
minMs: sorted[0],
|
|
36
|
-
maxMs: sorted.at(-1),
|
|
37
|
-
medianMs: p50Ms,
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
export async function sampleOperation(operation, options) {
|
|
41
|
-
const mode = options.mode ?? "warm";
|
|
42
|
-
const warmupCount = mode === "warm" ? (options.warmupCount ?? DEFAULT_WARMUP_COUNT) : 0;
|
|
43
|
-
const sampleCount = options.sampleCount ?? (mode === "warm" ? MIN_WARM_SAMPLES : DEFAULT_COLD_SAMPLES);
|
|
44
|
-
let value;
|
|
45
|
-
const call = async (kind, index) => {
|
|
46
|
-
const timeoutMs = options.timeoutMs ?? DEFAULT_CALL_TIMEOUT_MS;
|
|
47
|
-
let timer;
|
|
48
|
-
try {
|
|
49
|
-
return await Promise.race([
|
|
50
|
-
operation(),
|
|
51
|
-
new Promise((_, reject) => {
|
|
52
|
-
timer = setTimeout(async () => {
|
|
53
|
-
try {
|
|
54
|
-
if (options.onTimeout)
|
|
55
|
-
await options.onTimeout(kind, index);
|
|
56
|
-
else
|
|
57
|
-
reapDescendants(process.pid);
|
|
58
|
-
}
|
|
59
|
-
catch {
|
|
60
|
-
// Cleanup failure must not replace or strand the timeout result.
|
|
61
|
-
}
|
|
62
|
-
finally {
|
|
63
|
-
reject(new Error(`Competitive ${kind} call ${index + 1} timed out after ${timeoutMs}ms`));
|
|
64
|
-
}
|
|
65
|
-
}, timeoutMs);
|
|
66
|
-
timer.unref?.();
|
|
67
|
-
}),
|
|
68
|
-
]);
|
|
69
|
-
}
|
|
70
|
-
finally {
|
|
71
|
-
if (timer)
|
|
72
|
-
clearTimeout(timer);
|
|
73
|
-
}
|
|
74
|
-
};
|
|
75
|
-
for (let index = 0; index < warmupCount; index++) {
|
|
76
|
-
await options.beforeSample?.("warmup", index);
|
|
77
|
-
value = await call("warmup", index);
|
|
78
|
-
}
|
|
79
|
-
const samplesMs = [];
|
|
80
|
-
for (let index = 0; index < sampleCount; index++) {
|
|
81
|
-
await options.beforeSample?.("sample", index);
|
|
82
|
-
const startedAt = performance.now();
|
|
83
|
-
value = await call("sample", index);
|
|
84
|
-
samplesMs.push(Number((performance.now() - startedAt).toFixed(3)));
|
|
85
|
-
}
|
|
86
|
-
return {
|
|
87
|
-
value: value,
|
|
88
|
-
measurement: summarizeLatencySamples(mode, samplesMs, warmupCount),
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
export function reapDescendants(rootPid) {
|
|
92
|
-
const output = childProcess.spawnSync("ps", ["-axo", "pid=,ppid="]).stdout.toString();
|
|
93
|
-
const processes = output
|
|
94
|
-
.split("\n")
|
|
95
|
-
.map((line) => line.trim().split(/\s+/).map(Number))
|
|
96
|
-
.filter(([pid, parentPid]) => Number.isInteger(pid) && Number.isInteger(parentPid));
|
|
97
|
-
const descendants = new Set([rootPid]);
|
|
98
|
-
for (let changed = true; changed;) {
|
|
99
|
-
changed = false;
|
|
100
|
-
for (const [pid, parentPid] of processes) {
|
|
101
|
-
if (!descendants.has(pid) && descendants.has(parentPid)) {
|
|
102
|
-
descendants.add(pid);
|
|
103
|
-
changed = true;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
descendants.delete(rootPid);
|
|
108
|
-
for (const signal of ["-TERM", "-KILL"]) {
|
|
109
|
-
for (const pid of [...descendants].reverse()) {
|
|
110
|
-
childProcess.spawnSync("/bin/kill", [signal, String(pid)]);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
export function createCheckpointingResults(outputPath) {
|
|
115
|
-
const results = [];
|
|
116
|
-
results.push = (...items) => {
|
|
117
|
-
const length = Array.prototype.push.apply(results, items);
|
|
118
|
-
const temporary = `${outputPath}.partial-${process.pid}`;
|
|
119
|
-
fs.writeFileSync(temporary, `${JSON.stringify({
|
|
120
|
-
schemaVersion: 2,
|
|
121
|
-
status: "partial",
|
|
122
|
-
terminal: false,
|
|
123
|
-
partial: true,
|
|
124
|
-
generatedAt: new Date().toISOString(),
|
|
125
|
-
results,
|
|
126
|
-
}, null, 2)}\n`);
|
|
127
|
-
fs.renameSync(temporary, outputPath);
|
|
128
|
-
return length;
|
|
129
|
-
};
|
|
130
|
-
return results;
|
|
131
|
-
}
|
|
132
|
-
function emptyOwner() {
|
|
133
|
-
return { rssBytes: 0, pids: [] };
|
|
134
|
-
}
|
|
135
|
-
export function attributeProcessTree(processes, rootPid, patterns, phase, rootOwner = "harness") {
|
|
136
|
-
const descendants = new Set([rootPid]);
|
|
137
|
-
for (let changed = true; changed;) {
|
|
138
|
-
changed = false;
|
|
139
|
-
for (const process of processes) {
|
|
140
|
-
if (!descendants.has(process.pid) && descendants.has(process.parentPid)) {
|
|
141
|
-
descendants.add(process.pid);
|
|
142
|
-
changed = true;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
const result = {
|
|
147
|
-
phase,
|
|
148
|
-
harness: emptyOwner(),
|
|
149
|
-
knodin: emptyOwner(),
|
|
150
|
-
competitor: emptyOwner(),
|
|
151
|
-
unknown: emptyOwner(),
|
|
152
|
-
};
|
|
153
|
-
for (const process of processes) {
|
|
154
|
-
if (!descendants.has(process.pid))
|
|
155
|
-
continue;
|
|
156
|
-
const owner = process.pid === rootPid
|
|
157
|
-
? rootOwner
|
|
158
|
-
: patterns.knodin.some((pattern) => pattern.test(process.command))
|
|
159
|
-
? "knodin"
|
|
160
|
-
: patterns.competitor.some((pattern) => pattern.test(process.command))
|
|
161
|
-
? "competitor"
|
|
162
|
-
: "unknown";
|
|
163
|
-
result[owner].rssBytes += process.rssBytes;
|
|
164
|
-
result[owner].pids.push(process.pid);
|
|
165
|
-
}
|
|
166
|
-
return result;
|
|
167
|
-
}
|
|
168
|
-
export function mergeResourcePeaks(left, right) {
|
|
169
|
-
const merged = {
|
|
170
|
-
phase: right.phase,
|
|
171
|
-
harness: emptyOwner(),
|
|
172
|
-
knodin: emptyOwner(),
|
|
173
|
-
competitor: emptyOwner(),
|
|
174
|
-
unknown: emptyOwner(),
|
|
175
|
-
};
|
|
176
|
-
for (const owner of ["harness", "knodin", "competitor", "unknown"]) {
|
|
177
|
-
merged[owner] =
|
|
178
|
-
right[owner].rssBytes >= left[owner].rssBytes
|
|
179
|
-
? { ...right[owner], pids: [...right[owner].pids] }
|
|
180
|
-
: { ...left[owner], pids: [...left[owner].pids] };
|
|
181
|
-
}
|
|
182
|
-
return merged;
|
|
183
|
-
}
|
|
@@ -1,487 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { COMPETITIVE_MANIFEST, } from "./competitive-manifest.js";
|
|
4
|
-
const RESERVED_CASE_KEYS = new Set([
|
|
5
|
-
"id",
|
|
6
|
-
"axis",
|
|
7
|
-
"parameters",
|
|
8
|
-
"note",
|
|
9
|
-
"blocked",
|
|
10
|
-
"mutation",
|
|
11
|
-
"knodin",
|
|
12
|
-
"oracle",
|
|
13
|
-
"caseContract",
|
|
14
|
-
"partial",
|
|
15
|
-
]);
|
|
16
|
-
function responseOf(side) {
|
|
17
|
-
if (!side || side.ok !== true)
|
|
18
|
-
return null;
|
|
19
|
-
const response = side.response;
|
|
20
|
-
return typeof response === "string" && response.length > 0 ? response : null;
|
|
21
|
-
}
|
|
22
|
-
function normalizedWords(value) {
|
|
23
|
-
return new Set(value
|
|
24
|
-
.toLowerCase()
|
|
25
|
-
.split(/[^a-z0-9_.-]+/)
|
|
26
|
-
.filter((word) => word.length >= 4));
|
|
27
|
-
}
|
|
28
|
-
function runCheckedInOracle(oracleId, test, competitor) {
|
|
29
|
-
const contenderResponse = responseOf(findCompetitorSide(test, competitor));
|
|
30
|
-
const knodinResponse = responseOf(test.knodin);
|
|
31
|
-
if (!contenderResponse || !knodinResponse) {
|
|
32
|
-
return {
|
|
33
|
-
id: oracleId,
|
|
34
|
-
status: "unavailable",
|
|
35
|
-
reason: "Both successful response payloads are required for the checked-in oracle.",
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
const bothContain = (pattern) => pattern.test(contenderResponse) && pattern.test(knodinResponse);
|
|
39
|
-
let passed = false;
|
|
40
|
-
switch (oracleId) {
|
|
41
|
-
case "contains-create-engine":
|
|
42
|
-
passed = bothContain(/create[\s_-]*engine/i);
|
|
43
|
-
break;
|
|
44
|
-
case "create-engine-definition":
|
|
45
|
-
passed = bothContain(/create[\s_-]*engine/i) && bothContain(/src\/engine\/index\.ts/i);
|
|
46
|
-
break;
|
|
47
|
-
case "create-engine-callers":
|
|
48
|
-
passed = bothContain(/create[\s_-]*engine/i) && bothContain(/\bmain\b/i);
|
|
49
|
-
break;
|
|
50
|
-
case "create-engine-callees":
|
|
51
|
-
passed = bothContain(/create[\s_-]*engine/i) && bothContain(/withStaleness/i);
|
|
52
|
-
break;
|
|
53
|
-
case "create-engine-both":
|
|
54
|
-
passed =
|
|
55
|
-
bothContain(/create[\s_-]*engine/i) &&
|
|
56
|
-
bothContain(/\bmain\b/i) &&
|
|
57
|
-
bothContain(/withStaleness/i);
|
|
58
|
-
break;
|
|
59
|
-
case "freshness-search":
|
|
60
|
-
passed = bothContain(/index/i) && bothContain(/fresh(?:ness)?/i);
|
|
61
|
-
break;
|
|
62
|
-
case "engine-package":
|
|
63
|
-
passed = bothContain(/engine/i) && bothContain(/(?:package|module|community)/i);
|
|
64
|
-
break;
|
|
65
|
-
case "indexed-status": {
|
|
66
|
-
const indexed = (response) => /(?:total_files|indexedFiles)"?\s*:\s*[1-9]\d*/i.test(response);
|
|
67
|
-
passed = indexed(contenderResponse) && indexed(knodinResponse);
|
|
68
|
-
break;
|
|
69
|
-
}
|
|
70
|
-
case "contains-index":
|
|
71
|
-
passed = bothContain(/index|fresh|status/i);
|
|
72
|
-
break;
|
|
73
|
-
case "pack-two-files":
|
|
74
|
-
passed =
|
|
75
|
-
bothContain(/src\/context\.ts/i) &&
|
|
76
|
-
bothContain(/src\/cli-args\.ts/i) &&
|
|
77
|
-
!/(?:^|\/)[^/\n]*\.spec\.ts/i.test(contenderResponse) &&
|
|
78
|
-
!/(?:^|\/)[^/\n]*\.spec\.ts/i.test(knodinResponse);
|
|
79
|
-
break;
|
|
80
|
-
case "packed-read": {
|
|
81
|
-
const contenderWords = normalizedWords(contenderResponse);
|
|
82
|
-
const knodinWords = normalizedWords(knodinResponse);
|
|
83
|
-
const shared = [...contenderWords].filter((word) => knodinWords.has(word));
|
|
84
|
-
passed = shared.length >= 2;
|
|
85
|
-
break;
|
|
86
|
-
}
|
|
87
|
-
case "grep-create-engine":
|
|
88
|
-
passed = bothContain(/createEngine/i);
|
|
89
|
-
break;
|
|
90
|
-
case "architecture-facet": {
|
|
91
|
-
const facet = String(test.id ?? "")
|
|
92
|
-
.replace(/^architecture-/, "")
|
|
93
|
-
.replace("_", " ");
|
|
94
|
-
passed = facet.length > 0 && bothContain(new RegExp(facet.replace(" ", "[ _-]?"), "i"));
|
|
95
|
-
break;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
return {
|
|
99
|
-
id: oracleId,
|
|
100
|
-
status: passed ? "passed" : "failed",
|
|
101
|
-
...(passed ? {} : { reason: `Checked-in ${oracleId} oracle did not match both responses.` }),
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
export function applyCompetitiveCaseContracts(competitor, raw, fixtureRevision) {
|
|
105
|
-
const source = raw && typeof raw === "object"
|
|
106
|
-
? raw
|
|
107
|
-
: {};
|
|
108
|
-
const results = Array.isArray(source.results) ? source.results : [];
|
|
109
|
-
const mappings = COMPETITIVE_MANIFEST.find((entry) => entry.id === competitor)?.caseMappings ?? [];
|
|
110
|
-
return {
|
|
111
|
-
...source,
|
|
112
|
-
results: results.map((test) => {
|
|
113
|
-
const caseId = String(test.id ?? "");
|
|
114
|
-
const mapping = mappings.find((candidate) => new RegExp(candidate.idPattern).test(caseId));
|
|
115
|
-
if (!mapping) {
|
|
116
|
-
return {
|
|
117
|
-
...test,
|
|
118
|
-
caseContract: {
|
|
119
|
-
useCase: String(test.axis ?? test.id ?? "unlabeled competitive case"),
|
|
120
|
-
fixtureRevision,
|
|
121
|
-
mode: "warm",
|
|
122
|
-
scope: {
|
|
123
|
-
competitorOperation: "unmatched",
|
|
124
|
-
knodinOperation: "unmatched",
|
|
125
|
-
dimensions: [],
|
|
126
|
-
},
|
|
127
|
-
budgets: { bytes: null, tokens: null, items: null },
|
|
128
|
-
disposition: {
|
|
129
|
-
status: "incomparable",
|
|
130
|
-
reason: "No checked-in equivalent-operation mapping exists for this case ID; latency is excluded.",
|
|
131
|
-
},
|
|
132
|
-
oracle: {
|
|
133
|
-
status: "unavailable",
|
|
134
|
-
reason: "Correctness is not evaluated for an incomparable case.",
|
|
135
|
-
},
|
|
136
|
-
},
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
const dimensions = [...mapping.scope.dimensions];
|
|
140
|
-
const direction = caseId.match(/^trace-(inbound|outbound|both)-/)?.[1];
|
|
141
|
-
if (direction)
|
|
142
|
-
dimensions.push(`direction=${direction}`);
|
|
143
|
-
const facet = caseId.match(/^architecture-([a-z_]+)/)?.[1];
|
|
144
|
-
if (facet)
|
|
145
|
-
dimensions.push(`facet=${facet}`);
|
|
146
|
-
return {
|
|
147
|
-
...test,
|
|
148
|
-
caseContract: {
|
|
149
|
-
useCase: mapping.useCase,
|
|
150
|
-
fixtureRevision,
|
|
151
|
-
mode: caseId.endsWith("-cold") ? "cold" : mapping.mode,
|
|
152
|
-
scope: { ...mapping.scope, dimensions },
|
|
153
|
-
budgets: mapping.budgets,
|
|
154
|
-
disposition: { status: "comparable", reason: mapping.reason },
|
|
155
|
-
oracle: runCheckedInOracle(mapping.oracleId, test, competitor),
|
|
156
|
-
},
|
|
157
|
-
};
|
|
158
|
-
}),
|
|
159
|
-
};
|
|
160
|
-
}
|
|
161
|
-
export function selectCompetitors(manifest, explicitIds, roadmapIds) {
|
|
162
|
-
const known = new Set(manifest.map((entry) => entry.id));
|
|
163
|
-
for (const id of explicitIds) {
|
|
164
|
-
if (!known.has(id))
|
|
165
|
-
throw new Error(`Unknown competitor: ${id}`);
|
|
166
|
-
}
|
|
167
|
-
const requestedRoadmap = new Set(roadmapIds.map((id) => id.toUpperCase()));
|
|
168
|
-
const knownRoadmap = new Set(manifest.flatMap((entry) => [...entry.roadmap]).map((id) => id.toUpperCase()));
|
|
169
|
-
for (const id of requestedRoadmap) {
|
|
170
|
-
if (!knownRoadmap.has(id))
|
|
171
|
-
throw new Error(`Unknown roadmap item: ${id}`);
|
|
172
|
-
}
|
|
173
|
-
const selected = new Set(explicitIds);
|
|
174
|
-
for (const entry of manifest) {
|
|
175
|
-
if (entry.roadmap.some((id) => requestedRoadmap.has(id.toUpperCase())))
|
|
176
|
-
selected.add(entry.id);
|
|
177
|
-
}
|
|
178
|
-
if (selected.size === 0 && explicitIds.length === 0 && roadmapIds.length === 0) {
|
|
179
|
-
for (const entry of manifest)
|
|
180
|
-
selected.add(entry.id);
|
|
181
|
-
}
|
|
182
|
-
return manifest.filter((entry) => selected.has(entry.id)).map((entry) => entry.id);
|
|
183
|
-
}
|
|
184
|
-
export function createRunDirectory(root, timestamp, commit) {
|
|
185
|
-
const stamp = timestamp.replace(/[-:.]/g, "");
|
|
186
|
-
const directory = path.join(root, `${stamp}-${commit.slice(0, 12)}`);
|
|
187
|
-
try {
|
|
188
|
-
fs.mkdirSync(directory, { recursive: false });
|
|
189
|
-
}
|
|
190
|
-
catch (error) {
|
|
191
|
-
if (error.code === "EEXIST") {
|
|
192
|
-
throw new Error(`Competitive run directory already exists: ${directory}`);
|
|
193
|
-
}
|
|
194
|
-
throw error;
|
|
195
|
-
}
|
|
196
|
-
return directory;
|
|
197
|
-
}
|
|
198
|
-
function findCompetitorSide(test, competitor) {
|
|
199
|
-
const candidates = [
|
|
200
|
-
competitor,
|
|
201
|
-
competitor.replaceAll("-", ""),
|
|
202
|
-
competitor.replaceAll("-", "_"),
|
|
203
|
-
"competitor",
|
|
204
|
-
"gitnexus",
|
|
205
|
-
"graphify",
|
|
206
|
-
"serena",
|
|
207
|
-
"grepai",
|
|
208
|
-
"repomix",
|
|
209
|
-
"aider",
|
|
210
|
-
"code2prompt",
|
|
211
|
-
"claudeContext",
|
|
212
|
-
"codegraph",
|
|
213
|
-
];
|
|
214
|
-
for (const key of candidates) {
|
|
215
|
-
const value = test[key];
|
|
216
|
-
if (value && typeof value === "object" && ("ok" in value || "medianMs" in value)) {
|
|
217
|
-
return value;
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
for (const [key, value] of Object.entries(test)) {
|
|
221
|
-
if (RESERVED_CASE_KEYS.has(key) || !value || typeof value !== "object")
|
|
222
|
-
continue;
|
|
223
|
-
if ("ok" in value || "medianMs" in value)
|
|
224
|
-
return value;
|
|
225
|
-
}
|
|
226
|
-
return undefined;
|
|
227
|
-
}
|
|
228
|
-
export function normalizeRawResult(competitor, raw) {
|
|
229
|
-
const rawRecord = raw && typeof raw === "object"
|
|
230
|
-
? raw
|
|
231
|
-
: {};
|
|
232
|
-
const results = Array.isArray(rawRecord.results)
|
|
233
|
-
? (rawRecord.results ?? [])
|
|
234
|
-
: [];
|
|
235
|
-
const partialRun = rawRecord.partial === true || rawRecord.status === "partial";
|
|
236
|
-
let paired = 0;
|
|
237
|
-
let knodinFaster = 0;
|
|
238
|
-
let competitorFaster = 0;
|
|
239
|
-
let competitorErrors = 0;
|
|
240
|
-
let knodinErrors = 0;
|
|
241
|
-
let blocked = 0;
|
|
242
|
-
const ratios = [];
|
|
243
|
-
const precisions = [];
|
|
244
|
-
const recalls = [];
|
|
245
|
-
let oracleCases = 0;
|
|
246
|
-
let oraclePassed = 0;
|
|
247
|
-
let oracleFailed = 0;
|
|
248
|
-
let oracleUnavailable = 0;
|
|
249
|
-
let incomparable = 0;
|
|
250
|
-
let exactMatches = 0;
|
|
251
|
-
let exactMismatches = 0;
|
|
252
|
-
let falsePositives = 0;
|
|
253
|
-
let hasExactMatch = false;
|
|
254
|
-
let hasFalsePositives = false;
|
|
255
|
-
let knodinResponseBytes = 0;
|
|
256
|
-
let competitorResponseBytes = 0;
|
|
257
|
-
let hasKnodinResponseBytes = false;
|
|
258
|
-
let hasCompetitorResponseBytes = false;
|
|
259
|
-
const estimatedTokens = [];
|
|
260
|
-
const peakRssMb = [];
|
|
261
|
-
const knodinPeakRssMb = [];
|
|
262
|
-
const competitorPeakRssMb = [];
|
|
263
|
-
const diskBytes = [];
|
|
264
|
-
const modeRatios = {
|
|
265
|
-
cold: { p50: [], p95: [] },
|
|
266
|
-
warm: { p50: [], p95: [] },
|
|
267
|
-
};
|
|
268
|
-
const attributedResources = Array.isArray(rawRecord.resources)
|
|
269
|
-
? rawRecord.resources
|
|
270
|
-
: [];
|
|
271
|
-
for (const resource of attributedResources) {
|
|
272
|
-
for (const [owner, target] of [
|
|
273
|
-
["knodin", knodinPeakRssMb],
|
|
274
|
-
["competitor", competitorPeakRssMb],
|
|
275
|
-
]) {
|
|
276
|
-
const measurement = resource[owner];
|
|
277
|
-
if (measurement &&
|
|
278
|
-
typeof measurement === "object" &&
|
|
279
|
-
"rssBytes" in measurement &&
|
|
280
|
-
typeof measurement.rssBytes === "number" &&
|
|
281
|
-
measurement.rssBytes > 0) {
|
|
282
|
-
const megabytes = measurement.rssBytes / 1024 / 1024;
|
|
283
|
-
target.push(megabytes);
|
|
284
|
-
peakRssMb.push(megabytes);
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
for (const test of results) {
|
|
289
|
-
if (test.blocked)
|
|
290
|
-
blocked++;
|
|
291
|
-
const contender = findCompetitorSide(test, competitor);
|
|
292
|
-
const knodin = test.knodin;
|
|
293
|
-
if (contender && contender.ok === false)
|
|
294
|
-
competitorErrors++;
|
|
295
|
-
if (knodin && knodin.ok === false)
|
|
296
|
-
knodinErrors++;
|
|
297
|
-
const oracle = test.oracle;
|
|
298
|
-
const contract = test.caseContract;
|
|
299
|
-
if (contract?.disposition.status === "incomparable")
|
|
300
|
-
incomparable++;
|
|
301
|
-
if (!test.blocked) {
|
|
302
|
-
if (contract?.disposition.status === "comparable") {
|
|
303
|
-
oracleCases++;
|
|
304
|
-
if (contract.oracle.status === "passed")
|
|
305
|
-
oraclePassed++;
|
|
306
|
-
else if (contract.oracle.status === "failed")
|
|
307
|
-
oracleFailed++;
|
|
308
|
-
else
|
|
309
|
-
oracleUnavailable++;
|
|
310
|
-
}
|
|
311
|
-
else if (!contract) {
|
|
312
|
-
oracleUnavailable++;
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
if (oracle && typeof oracle === "object") {
|
|
316
|
-
if (contract?.disposition.status !== "comparable")
|
|
317
|
-
oracleCases++;
|
|
318
|
-
if (typeof oracle.exactMatch === "boolean") {
|
|
319
|
-
hasExactMatch = true;
|
|
320
|
-
if (oracle.exactMatch)
|
|
321
|
-
exactMatches++;
|
|
322
|
-
else
|
|
323
|
-
exactMismatches++;
|
|
324
|
-
}
|
|
325
|
-
if (typeof oracle.precision === "number")
|
|
326
|
-
precisions.push(oracle.precision);
|
|
327
|
-
if (typeof oracle.recall === "number")
|
|
328
|
-
recalls.push(oracle.recall);
|
|
329
|
-
if (typeof oracle.falsePositives === "number") {
|
|
330
|
-
hasFalsePositives = true;
|
|
331
|
-
falsePositives += oracle.falsePositives;
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
if (typeof knodin?.responseBytes === "number") {
|
|
335
|
-
hasKnodinResponseBytes = true;
|
|
336
|
-
knodinResponseBytes += knodin.responseBytes;
|
|
337
|
-
}
|
|
338
|
-
if (typeof contender?.responseBytes === "number") {
|
|
339
|
-
hasCompetitorResponseBytes = true;
|
|
340
|
-
competitorResponseBytes += contender.responseBytes;
|
|
341
|
-
}
|
|
342
|
-
for (const value of [knodin?.estimatedTokens, contender?.estimatedTokens])
|
|
343
|
-
if (typeof value === "number")
|
|
344
|
-
estimatedTokens.push(value);
|
|
345
|
-
if (typeof knodin?.peakRssMb === "number") {
|
|
346
|
-
peakRssMb.push(knodin.peakRssMb);
|
|
347
|
-
knodinPeakRssMb.push(knodin.peakRssMb);
|
|
348
|
-
}
|
|
349
|
-
if (typeof contender?.peakRssMb === "number") {
|
|
350
|
-
peakRssMb.push(contender.peakRssMb);
|
|
351
|
-
competitorPeakRssMb.push(contender.peakRssMb);
|
|
352
|
-
}
|
|
353
|
-
for (const value of [knodin?.diskBytes, contender?.diskBytes])
|
|
354
|
-
if (typeof value === "number")
|
|
355
|
-
diskBytes.push(value);
|
|
356
|
-
if (!partialRun &&
|
|
357
|
-
test.partial !== true &&
|
|
358
|
-
contract?.disposition.status === "comparable" &&
|
|
359
|
-
contract.oracle.status === "passed" &&
|
|
360
|
-
contender?.ok === true &&
|
|
361
|
-
knodin?.ok === true &&
|
|
362
|
-
typeof contender.medianMs === "number" &&
|
|
363
|
-
typeof knodin.medianMs === "number" &&
|
|
364
|
-
knodin.medianMs > 0) {
|
|
365
|
-
const mode = contract.mode;
|
|
366
|
-
const contenderP50 = contender.p50Ms ?? contender.medianMs;
|
|
367
|
-
const knodinP50 = knodin.p50Ms ?? knodin.medianMs;
|
|
368
|
-
paired++;
|
|
369
|
-
if (contender.medianMs < knodin.medianMs)
|
|
370
|
-
competitorFaster++;
|
|
371
|
-
else if (knodin.medianMs < contender.medianMs)
|
|
372
|
-
knodinFaster++;
|
|
373
|
-
ratios.push(contender.medianMs / knodin.medianMs);
|
|
374
|
-
if (knodinP50 > 0)
|
|
375
|
-
modeRatios[mode].p50.push(contenderP50 / knodinP50);
|
|
376
|
-
if (typeof contender.p95Ms === "number" &&
|
|
377
|
-
typeof knodin.p95Ms === "number" &&
|
|
378
|
-
knodin.p95Ms > 0) {
|
|
379
|
-
modeRatios[mode].p95.push(contender.p95Ms / knodin.p95Ms);
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
ratios.sort((a, b) => a - b);
|
|
384
|
-
const median = (values) => {
|
|
385
|
-
const sorted = [...values].sort((left, right) => left - right);
|
|
386
|
-
return sorted.length ? sorted[Math.floor(sorted.length / 2)] : null;
|
|
387
|
-
};
|
|
388
|
-
return {
|
|
389
|
-
competitor,
|
|
390
|
-
cases: results.length,
|
|
391
|
-
paired,
|
|
392
|
-
knodinFaster,
|
|
393
|
-
competitorFaster,
|
|
394
|
-
competitorErrors,
|
|
395
|
-
knodinErrors,
|
|
396
|
-
blocked,
|
|
397
|
-
medianRatio: ratios.length ? ratios[Math.floor(ratios.length / 2)] : null,
|
|
398
|
-
correctness: {
|
|
399
|
-
oracleCases,
|
|
400
|
-
oraclePassed,
|
|
401
|
-
oracleFailed,
|
|
402
|
-
oracleUnavailable,
|
|
403
|
-
incomparable,
|
|
404
|
-
exactMatches: hasExactMatch ? exactMatches : null,
|
|
405
|
-
exactMismatches: hasExactMatch ? exactMismatches : null,
|
|
406
|
-
precision: precisions.length
|
|
407
|
-
? precisions.reduce((sum, value) => sum + value, 0) / precisions.length
|
|
408
|
-
: null,
|
|
409
|
-
recall: recalls.length
|
|
410
|
-
? recalls.reduce((sum, value) => sum + value, 0) / recalls.length
|
|
411
|
-
: null,
|
|
412
|
-
falsePositives: hasFalsePositives ? falsePositives : null,
|
|
413
|
-
},
|
|
414
|
-
performance: {
|
|
415
|
-
latencySamples: ratios.length,
|
|
416
|
-
modes: Object.fromEntries(["cold", "warm"]
|
|
417
|
-
.filter((mode) => modeRatios[mode].p50.length > 0)
|
|
418
|
-
.map((mode) => [
|
|
419
|
-
mode,
|
|
420
|
-
{
|
|
421
|
-
paired: modeRatios[mode].p50.length,
|
|
422
|
-
p50Ratio: median(modeRatios[mode].p50),
|
|
423
|
-
p95Ratio: median(modeRatios[mode].p95),
|
|
424
|
-
},
|
|
425
|
-
])),
|
|
426
|
-
knodinResponseBytes: hasKnodinResponseBytes ? knodinResponseBytes : null,
|
|
427
|
-
competitorResponseBytes: hasCompetitorResponseBytes ? competitorResponseBytes : null,
|
|
428
|
-
estimatedTokens: estimatedTokens.length
|
|
429
|
-
? estimatedTokens.reduce((sum, value) => sum + value, 0)
|
|
430
|
-
: null,
|
|
431
|
-
knodinPeakRssMb: knodinPeakRssMb.length ? Math.max(...knodinPeakRssMb) : null,
|
|
432
|
-
competitorPeakRssMb: competitorPeakRssMb.length ? Math.max(...competitorPeakRssMb) : null,
|
|
433
|
-
peakRssMb: peakRssMb.length ? Math.max(...peakRssMb) : null,
|
|
434
|
-
diskBytes: diskBytes.length ? Math.max(...diskBytes) : null,
|
|
435
|
-
},
|
|
436
|
-
};
|
|
437
|
-
}
|
|
438
|
-
export function compareSummaries(baseline, current, latencyTolerance = 0.1) {
|
|
439
|
-
if (!Number.isFinite(latencyTolerance) || latencyTolerance < 0) {
|
|
440
|
-
throw new Error("Latency tolerance must be a non-negative number");
|
|
441
|
-
}
|
|
442
|
-
const reasons = [];
|
|
443
|
-
if (current.paired < baseline.paired)
|
|
444
|
-
reasons.push(`Paired cases fell by ${baseline.paired - current.paired}`);
|
|
445
|
-
if (current.knodinFaster < baseline.knodinFaster) {
|
|
446
|
-
reasons.push(`knodin wins fell by ${baseline.knodinFaster - current.knodinFaster}`);
|
|
447
|
-
}
|
|
448
|
-
if (current.knodinErrors > baseline.knodinErrors) {
|
|
449
|
-
reasons.push(`knodin errors increased by ${current.knodinErrors - baseline.knodinErrors}`);
|
|
450
|
-
}
|
|
451
|
-
if (baseline.performance && current.performance) {
|
|
452
|
-
for (const mode of ["cold", "warm"]) {
|
|
453
|
-
const before = baseline.performance.modes?.[mode];
|
|
454
|
-
const after = current.performance.modes?.[mode];
|
|
455
|
-
if (!before || !after)
|
|
456
|
-
continue;
|
|
457
|
-
for (const percentile of ["p50Ratio", "p95Ratio"]) {
|
|
458
|
-
const beforeValue = before[percentile];
|
|
459
|
-
const afterValue = after[percentile];
|
|
460
|
-
if (beforeValue !== null &&
|
|
461
|
-
afterValue !== null &&
|
|
462
|
-
afterValue < beforeValue * (1 - latencyTolerance)) {
|
|
463
|
-
reasons.push(`${mode} ${percentile.replace("Ratio", "")} competitor/knodin ratio fell from ${beforeValue.toFixed(3)} to ${afterValue.toFixed(3)}`);
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
else if (baseline.medianRatio !== null &&
|
|
469
|
-
current.medianRatio !== null &&
|
|
470
|
-
current.medianRatio < baseline.medianRatio * (1 - latencyTolerance)) {
|
|
471
|
-
reasons.push(`Competitor/knodin median ratio fell from ${baseline.medianRatio.toFixed(3)} to ${current.medianRatio.toFixed(3)}`);
|
|
472
|
-
}
|
|
473
|
-
return {
|
|
474
|
-
regressed: reasons.length > 0,
|
|
475
|
-
reasons,
|
|
476
|
-
deltas: {
|
|
477
|
-
paired: current.paired - baseline.paired,
|
|
478
|
-
knodinFaster: current.knodinFaster - baseline.knodinFaster,
|
|
479
|
-
competitorFaster: current.competitorFaster - baseline.competitorFaster,
|
|
480
|
-
competitorErrors: current.competitorErrors - baseline.competitorErrors,
|
|
481
|
-
knodinErrors: current.knodinErrors - baseline.knodinErrors,
|
|
482
|
-
medianRatio: baseline.medianRatio === null || current.medianRatio === null
|
|
483
|
-
? null
|
|
484
|
-
: current.medianRatio - baseline.medianRatio,
|
|
485
|
-
},
|
|
486
|
-
};
|
|
487
|
-
}
|