harness-everything 0.28.0 → 0.29.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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +12 -0
- package/benchmarks/fixtures/system-one-holdout-reviews.json +18 -18
- package/benchmarks/fixtures/system-one-holdout.json +9 -9
- package/benchmarks/results/system-one/harness-routing-v1-cpu-2026-09-24/README.md +75 -0
- package/benchmarks/results/system-one/harness-routing-v1-cpu-2026-09-24/report.json +10832 -0
- package/benchmarks/results/system-one/harness-routing-v1-ngram-2026-09-24/README.md +72 -0
- package/benchmarks/results/system-one/harness-routing-v1-ngram-2026-09-24/report.json +10817 -0
- package/benchmarks/results/system-one/harness-routing-v3-ngram-2026-09-24/README.md +63 -0
- package/benchmarks/results/system-one/harness-routing-v3-ngram-2026-09-24/report.json +10817 -0
- package/benchmarks/results/system-one/labeler-holdout-check-2026-09-24/report.json +1104 -0
- package/benchmarks/results/system-one/labeler-holdout-check-codex-2026-09-24/report.json +1104 -0
- package/benchmarks/results/system-one/labeler-holdout-check-codex-tier3-2026-09-24/report.json +1104 -0
- package/ci/mechanism-system-one-evaluation.test.js +17 -0
- package/ci/mechanism-system-one-label.test.js +27 -0
- package/ci/mechanism-system-one-ngram.test.js +161 -0
- package/ci/mechanism-system-one-train.test.js +12 -0
- package/ci/system-one-ngram-parity.py +19 -0
- package/ci/system-one-train-test.py +6 -0
- package/docs/system-one-corpus.md +31 -3
- package/docs/system-one-routing.md +84 -2
- package/docs/system-one-training.md +14 -2
- package/harness-everything/SKILL.md +1 -1
- package/harness-everything/scripts/system-one/evaluate.js +3 -2
- package/harness-everything/scripts/system-one/ngram.js +84 -0
- package/harness-everything/scripts/system-one/provider.js +15 -5
- package/opencode-plugin/plugin.json +1 -1
- package/package.json +1 -1
- package/plugins/harness-everything/.codex-plugin/plugin.json +1 -1
- package/plugins/harness-everything/plugin.json +1 -1
- package/plugins/harness-everything/skills/harness-everything/SKILL.md +1 -1
- package/plugins/harness-everything/skills/harness-everything/scripts/system-one/evaluate.js +3 -2
- package/plugins/harness-everything/skills/harness-everything/scripts/system-one/ngram.js +84 -0
- package/plugins/harness-everything/skills/harness-everything/scripts/system-one/provider.js +15 -5
- package/sbom.cdx.json +7 -7
- package/scripts/evaluate-system-one.js +16 -9
- package/scripts/system-one-calibrate.js +1 -1
- package/scripts/system-one-label.js +32 -3
- package/scripts/system-one-train-ngram.py +129 -0
- package/scripts/system-one-train.py +14 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
|
|
3
3
|
"name": "harness-everything",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.29.0",
|
|
5
5
|
"description": "Invariant-first engineering harness for routing, verification, and failure recovery while preserving agent autonomy.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Miya Daniel",
|
|
@@ -84,12 +84,13 @@ function evaluate(corpus, records, sourceEvidence = null) {
|
|
|
84
84
|
const gates = {
|
|
85
85
|
reviewedHoldout: cases.length >= 200 && cases.every(c => c.reviewed)
|
|
86
86
|
&& ['en', 'zh-TW'].every(lang => cases.filter(c => c.language === lang).length >= 50),
|
|
87
|
-
acceptedPrecision: model.acceptedPrecision !== null && model.acceptedPrecision >= 0.
|
|
87
|
+
acceptedPrecision: model.acceptedPrecision !== null && model.acceptedPrecision >= 0.85,
|
|
88
88
|
coverage: model.coverage >= 0.8,
|
|
89
89
|
macroF1: model.macroF1 >= baseline.macroF1,
|
|
90
90
|
repeatability: agreement === 1,
|
|
91
91
|
warmLatency: warm.length >= cases.length && latency.warmP95Ms <= 100,
|
|
92
|
-
sourceProvenance: sourceEvidence?.status === 'recorded' && sourceEvidence.provenance?.cuaS1?.sourceRevisionStatus === 'pinned'
|
|
92
|
+
sourceProvenance: sourceEvidence?.status === 'recorded' && (sourceEvidence.provenance?.cuaS1?.sourceRevisionStatus === 'pinned'
|
|
93
|
+
|| (sourceEvidence.transport === 'ngram' && sourceEvidence.artifactVerified === true)),
|
|
93
94
|
policyEvidence: false,
|
|
94
95
|
liveHostEvidence: false,
|
|
95
96
|
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
// In-process System One scorer: hashed character n-grams + a linear layer (docs/system-one-routing.md, "N-gram provider").
|
|
3
|
+
// Featurization must match scripts/system-one-train-ngram.py exactly; ci/mechanism-system-one-ngram.test.js proves it.
|
|
4
|
+
const fs = require('node:fs');
|
|
5
|
+
const { createHash } = require('node:crypto');
|
|
6
|
+
|
|
7
|
+
const SIDE_KEYS = ['format', 'formatVersion', 'dim', 'nmax', 'hash', 'catalog', 'bias', 'metadata'];
|
|
8
|
+
const cache = new Map();
|
|
9
|
+
const configError = () => Object.assign(new Error('provider-config'), { code: 'provider-config' });
|
|
10
|
+
const sha = buf => createHash('sha256').update(buf).digest('hex');
|
|
11
|
+
|
|
12
|
+
function fnv1a32(text) {
|
|
13
|
+
let h = 0x811c9dc5;
|
|
14
|
+
for (const byte of Buffer.from(text, 'utf8')) { h ^= byte; h = Math.imul(h, 0x01000193) >>> 0; }
|
|
15
|
+
return h >>> 0;
|
|
16
|
+
}
|
|
17
|
+
// Map of bucket -> weight: log(1 + count) per code-point n-gram, one length bucket, L2-normalized.
|
|
18
|
+
function featurize(text, nmax, dim) {
|
|
19
|
+
const t = text.toLowerCase().split(/\s+/).filter(Boolean).join(' ');
|
|
20
|
+
const cps = Array.from(t);
|
|
21
|
+
const counts = new Map();
|
|
22
|
+
for (let n = 1; n <= nmax; n++) {
|
|
23
|
+
for (let i = 0; i + n <= cps.length; i++) {
|
|
24
|
+
const gram = cps.slice(i, i + n).join('');
|
|
25
|
+
if (!gram.trim()) continue;
|
|
26
|
+
const b = fnv1a32(`${n}:${gram}`) % dim;
|
|
27
|
+
counts.set(b, (counts.get(b) || 0) + 1);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
const k = Math.min(8, Math.floor(Math.log2(Buffer.byteLength(t, 'utf8') + 1)));
|
|
31
|
+
counts.set(fnv1a32(`len:${k}`) % dim, 1);
|
|
32
|
+
const feats = new Map();
|
|
33
|
+
let norm = 0;
|
|
34
|
+
for (const [b, c] of counts) { const v = Math.log1p(c); feats.set(b, v); norm += v * v; }
|
|
35
|
+
norm = Math.sqrt(norm);
|
|
36
|
+
for (const [b, v] of feats) feats.set(b, v / norm);
|
|
37
|
+
return feats;
|
|
38
|
+
}
|
|
39
|
+
function validSidecar(s) {
|
|
40
|
+
const isPow2 = n => Number.isInteger(n) && n >= 1024 && n <= 1 << 20 && (n & (n - 1)) === 0;
|
|
41
|
+
return s && typeof s === 'object' && !Array.isArray(s) && Object.keys(s).length === SIDE_KEYS.length && SIDE_KEYS.every(k => Object.hasOwn(s, k))
|
|
42
|
+
&& s.format === 'harness-ngram' && s.formatVersion === 1 && isPow2(s.dim) && Number.isInteger(s.nmax) && s.nmax >= 1 && s.nmax <= 4
|
|
43
|
+
&& s.hash === 'fnv1a32' && Array.isArray(s.catalog) && s.catalog.length >= 2 && new Set(s.catalog).size === s.catalog.length
|
|
44
|
+
&& s.catalog.every(id => typeof id === 'string' && /^[a-z0-9._-]{1,80}$/.test(id))
|
|
45
|
+
&& Array.isArray(s.bias) && s.bias.length === s.catalog.length && s.bias.every(Number.isFinite)
|
|
46
|
+
&& s.metadata && typeof s.metadata === 'object' && !Array.isArray(s.metadata);
|
|
47
|
+
}
|
|
48
|
+
// Loads and verifies the artifact once per process; any mismatch throws provider-config.
|
|
49
|
+
function loadModel(manifest) {
|
|
50
|
+
const key = `${manifest.checkpoint}|${manifest.weightsSha256}|${manifest.configSha256}`;
|
|
51
|
+
if (cache.has(key)) return cache.get(key);
|
|
52
|
+
const sidecarPath = manifest.checkpoint.replace(/\.bin$/, '.json');
|
|
53
|
+
let side; let bin;
|
|
54
|
+
try {
|
|
55
|
+
const raw = fs.readFileSync(sidecarPath);
|
|
56
|
+
if (raw.length > 65536 || sha(raw) !== manifest.configSha256) throw configError();
|
|
57
|
+
side = JSON.parse(raw.toString('utf8'));
|
|
58
|
+
bin = fs.readFileSync(manifest.checkpoint);
|
|
59
|
+
} catch (_) { throw configError(); }
|
|
60
|
+
if (sha(bin) !== manifest.weightsSha256 || !validSidecar(side) || bin.length !== side.dim * side.catalog.length * 4) throw configError();
|
|
61
|
+
const W = new Float32Array(side.dim * side.catalog.length);
|
|
62
|
+
for (let i = 0; i < W.length; i++) W[i] = bin.readFloatLE(i * 4);
|
|
63
|
+
const model = { dim: side.dim, nmax: side.nmax, catalog: side.catalog, bias: side.bias, W };
|
|
64
|
+
cache.set(key, model);
|
|
65
|
+
return model;
|
|
66
|
+
}
|
|
67
|
+
function score(request, manifest) {
|
|
68
|
+
const model = loadModel(manifest);
|
|
69
|
+
const C = model.catalog.length;
|
|
70
|
+
if (request.options.length !== C || request.options.some((o, i) => o.id !== model.catalog[i])) throw configError();
|
|
71
|
+
const logits = model.bias.slice();
|
|
72
|
+
for (const [b, v] of featurize(request.context, model.nmax, model.dim)) {
|
|
73
|
+
for (let c = 0; c < C; c++) logits[c] += v * model.W[b * C + c];
|
|
74
|
+
}
|
|
75
|
+
const max = Math.max(...logits);
|
|
76
|
+
const exps = logits.map(z => Math.exp(z - max));
|
|
77
|
+
const sum = exps.reduce((s, x) => s + x, 0);
|
|
78
|
+
return {
|
|
79
|
+
schemaVersion: 1, requestHash: request.requestHash, catalogHash: request.catalogHash,
|
|
80
|
+
model: { id: manifest.modelId, revision: manifest.revision, domain: manifest.domain },
|
|
81
|
+
scores: request.options.map((o, i) => ({ id: o.id, probability: exps[i] / sum })),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
module.exports = { fnv1a32, featurize, loadModel, score };
|
|
@@ -17,15 +17,18 @@ const validAcceptance = a => exact(a, ['minConfidence', 'minMargin']) && inRange
|
|
|
17
17
|
const withAcceptance = (result, manifest) => (result && result.status === 'scored' && manifest.acceptance
|
|
18
18
|
? { ...result, acceptance: { ...manifest.acceptance } } : result);
|
|
19
19
|
function validateManifest(m) {
|
|
20
|
-
|
|
20
|
+
// The in-process ngram transport needs no Python and loads a .bin; the others run the CUA-S1 adapter.
|
|
21
|
+
const ngram = !!m && m.transport === 'ngram';
|
|
22
|
+
const required = ['schemaVersion', ...(ngram ? [] : ['python']), 'checkpoint', 'weightsSha256', 'configSha256', 'modelId', 'revision', 'domain'];
|
|
23
|
+
const strings = ['modelId', 'revision', 'domain', ...(ngram && !Object.hasOwn(m, 'python') ? [] : ['python'])];
|
|
21
24
|
if (!m || typeof m !== 'object' || Array.isArray(m) || required.some(k => !Object.hasOwn(m, k))
|
|
22
|
-
|| Object.keys(m).some(k => ![...required, 'timeoutMs', 'transport', 'idleTimeoutMs', 'acceptance'].includes(k)) || m.schemaVersion !== 1
|
|
25
|
+
|| Object.keys(m).some(k => ![...required, 'python', 'timeoutMs', 'transport', 'idleTimeoutMs', 'acceptance'].includes(k)) || m.schemaVersion !== 1
|
|
23
26
|
|| (m.acceptance !== undefined && !validAcceptance(m.acceptance))
|
|
24
|
-
||
|
|
25
|
-
|| typeof m.checkpoint !== 'string' || !path.isAbsolute(m.checkpoint) || path.extname(m.checkpoint) !== '.safetensors'
|
|
27
|
+
|| strings.some(k => typeof m[k] !== 'string' || !m[k].trim() || m[k].length > 4096 || m[k].includes('\0'))
|
|
28
|
+
|| typeof m.checkpoint !== 'string' || !path.isAbsolute(m.checkpoint) || path.extname(m.checkpoint) !== (ngram ? '.bin' : '.safetensors')
|
|
26
29
|
|| ['weightsSha256', 'configSha256'].some(k => typeof m[k] !== 'string' || !/^[a-f0-9]{64}$/.test(m[k]))
|
|
27
30
|
|| (m.timeoutMs !== undefined && (!Number.isInteger(m.timeoutMs) || m.timeoutMs < 1 || m.timeoutMs > 10000))
|
|
28
|
-
|| (m.transport !== undefined && !['oneshot', 'resident'].includes(m.transport))
|
|
31
|
+
|| (m.transport !== undefined && !['oneshot', 'resident', 'ngram'].includes(m.transport))
|
|
29
32
|
|| (m.idleTimeoutMs !== undefined && (!Number.isInteger(m.idleTimeoutMs) || m.idleTimeoutMs < 60000 || m.idleTimeoutMs > 14400000))
|
|
30
33
|
|| (m.modelId === 'cua-ai/cua-s1-forms' && m.domain !== 'forms-v1')) throw new TypeError('invalid-manifest');
|
|
31
34
|
return true;
|
|
@@ -57,15 +60,22 @@ function score(request, manifestPath) {
|
|
|
57
60
|
validateRequest(request);
|
|
58
61
|
let manifest;
|
|
59
62
|
try { manifest = readManifest(manifestPath); } catch (_) { return unavailable('provider-config'); }
|
|
63
|
+
if (manifest.transport === 'ngram') return withAcceptance(inProcess(request, manifest), manifest);
|
|
60
64
|
if (manifest.transport === 'resident') return withAcceptance(require('./resident').score({ ...request }, manifest, manifestPath), manifest);
|
|
61
65
|
return withAcceptance(oneShot(request, manifest), manifest);
|
|
62
66
|
}
|
|
67
|
+
// The ngram transport scores in this process; an artifact mismatch is a configuration error, never a score.
|
|
68
|
+
function inProcess(request, manifest) {
|
|
69
|
+
try { return { status: 'scored', response: require('./ngram').score({ ...request }, manifest) }; }
|
|
70
|
+
catch (_) { return unavailable('provider-config'); }
|
|
71
|
+
}
|
|
63
72
|
// Async callers (the hook entry) reach a resident server without the sync worker bridge.
|
|
64
73
|
// One-shot has no server to overlap with, so it runs the same child synchronously.
|
|
65
74
|
async function scoreAsync(request, manifestPath) {
|
|
66
75
|
validateRequest(request);
|
|
67
76
|
let manifest;
|
|
68
77
|
try { manifest = readManifest(manifestPath); } catch (_) { return unavailable('provider-config'); }
|
|
78
|
+
if (manifest.transport === 'ngram') return withAcceptance(inProcess(request, manifest), manifest);
|
|
69
79
|
if (manifest.transport === 'resident') return withAcceptance(await require('./resident').scoreAsync({ ...request }, manifest, manifestPath), manifest);
|
|
70
80
|
return withAcceptance(oneShot(request, manifest), manifest);
|
|
71
81
|
}
|
package/sbom.cdx.json
CHANGED
|
@@ -2,23 +2,23 @@
|
|
|
2
2
|
"$schema": "https://cyclonedx.org/schema/bom-1.7.schema.json",
|
|
3
3
|
"bomFormat": "CycloneDX",
|
|
4
4
|
"specVersion": "1.7",
|
|
5
|
-
"serialNumber": "urn:uuid:
|
|
5
|
+
"serialNumber": "urn:uuid:03c78df6-955e-5903-b3d9-620c6be8e2d4",
|
|
6
6
|
"version": 1,
|
|
7
7
|
"metadata": {
|
|
8
|
-
"timestamp": "2026-09-
|
|
8
|
+
"timestamp": "2026-09-28T01:49:53.842Z",
|
|
9
9
|
"tools": [
|
|
10
10
|
{
|
|
11
11
|
"vendor": "Harness Everything",
|
|
12
12
|
"name": "generate-sbom.js",
|
|
13
|
-
"version": "0.
|
|
13
|
+
"version": "0.29.0"
|
|
14
14
|
}
|
|
15
15
|
],
|
|
16
16
|
"component": {
|
|
17
17
|
"type": "application",
|
|
18
|
-
"bom-ref": "pkg:npm/harness-everything@0.
|
|
18
|
+
"bom-ref": "pkg:npm/harness-everything@0.29.0",
|
|
19
19
|
"name": "harness-everything",
|
|
20
|
-
"version": "0.
|
|
21
|
-
"purl": "pkg:npm/harness-everything@0.
|
|
20
|
+
"version": "0.29.0",
|
|
21
|
+
"purl": "pkg:npm/harness-everything@0.29.0"
|
|
22
22
|
}
|
|
23
23
|
},
|
|
24
24
|
"components": [
|
|
@@ -1999,7 +1999,7 @@
|
|
|
1999
1999
|
]
|
|
2000
2000
|
},
|
|
2001
2001
|
{
|
|
2002
|
-
"ref": "pkg:npm/harness-everything@0.
|
|
2002
|
+
"ref": "pkg:npm/harness-everything@0.29.0",
|
|
2003
2003
|
"dependsOn": [
|
|
2004
2004
|
"pkg:npm/%40commitlint/cli@19.8.1",
|
|
2005
2005
|
"pkg:npm/%40commitlint/config-conventional@19.8.1",
|
|
@@ -13,10 +13,15 @@ async function run(corpus, manifest) {
|
|
|
13
13
|
validateCorpus(corpus);
|
|
14
14
|
let config = null;
|
|
15
15
|
try { config = readManifest(manifest); } catch (_) { /* Missing provider remains an explicit unavailable measurement. */ }
|
|
16
|
-
// Resident runs are measured only after readiness
|
|
17
|
-
|
|
18
|
-
const
|
|
19
|
-
const
|
|
16
|
+
// Resident runs are measured only after readiness and ngram scores in process after one verified load,
|
|
17
|
+
// so their samples are warm; one-shot samples are cold.
|
|
18
|
+
const isResident = config?.transport === 'resident';
|
|
19
|
+
const isNgram = config?.transport === 'ngram';
|
|
20
|
+
const warm = isResident || isNgram;
|
|
21
|
+
const wasRunning = isResident && resident.status(config, manifest).running;
|
|
22
|
+
const ready = isResident && resident.ensureReady(config, manifest, 60000);
|
|
23
|
+
let artifactVerified = false;
|
|
24
|
+
if (isNgram) { try { require('../harness-everything/scripts/system-one/ngram').loadModel(config); artifactVerified = true; } catch (_) { /* recorded below */ } }
|
|
20
25
|
const records = [];
|
|
21
26
|
const originalMode = process.env.HARNESS_SYSTEM_ONE_MODE;
|
|
22
27
|
const originalLog = console.log;
|
|
@@ -37,7 +42,7 @@ async function run(corpus, manifest) {
|
|
|
37
42
|
records.push({ id: c.id, baseline: tier === 'unclassified' ? null : tier, runs });
|
|
38
43
|
}
|
|
39
44
|
} finally {
|
|
40
|
-
if (
|
|
45
|
+
if (isResident && !wasRunning) resident.stop(config, manifest);
|
|
41
46
|
console.log = originalLog;
|
|
42
47
|
if (originalMode === undefined) delete process.env.HARNESS_SYSTEM_ONE_MODE;
|
|
43
48
|
else process.env.HARNESS_SYSTEM_ONE_MODE = originalMode;
|
|
@@ -47,11 +52,13 @@ async function run(corpus, manifest) {
|
|
|
47
52
|
const m = JSON.parse(fs.readFileSync(manifest, 'utf8'));
|
|
48
53
|
artifact = { declaredModelId: m.modelId, declaredRevision: m.revision, weightsSha256: m.weightsSha256, configSha256: m.configSha256 };
|
|
49
54
|
} catch (_) { /* Missing provider remains an explicit unavailable measurement. */ }
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
55
|
+
// The ngram transport has no Python package to probe; its provenance is the hash-verified artifact.
|
|
56
|
+
const source = isNgram ? { status: 'recorded', transport: 'ngram', artifactVerified } : provenance(manifest);
|
|
57
|
+
const kind = isNgram ? 'offline-ngram' : isResident ? 'offline-resident' : 'offline-one-shot';
|
|
58
|
+
return { ...evaluate(corpus, records, source), evidence: { kind, artifact, source,
|
|
59
|
+
residentReady: isResident ? ready : null,
|
|
53
60
|
environment: { cpu: os.cpus()[0]?.model || 'unknown', os: `${os.platform()} ${os.release()} ${os.arch()}`, node: process.version,
|
|
54
|
-
python: source.status === 'recorded' ? source.provenance.python : null, threads: 1 },
|
|
61
|
+
python: source.status === 'recorded' && source.provenance ? source.provenance.python : null, threads: 1 },
|
|
55
62
|
limitations: ['No independently verified holdout review', ...(warm ? [] : ['No warm inference measurement']), 'No live-host or policy evidence'] }, records };
|
|
56
63
|
}
|
|
57
64
|
if (require.main === module) {
|
|
@@ -13,7 +13,7 @@ function decideRow(probs, { minConfidence, minMargin }) {
|
|
|
13
13
|
if (margin === 0 || top[0] < minConfidence || margin < minMargin || IDS[top[1]] === 'unclassified') return null;
|
|
14
14
|
return IDS[top[1]];
|
|
15
15
|
}
|
|
16
|
-
function calibrate(rows, { minPrecision = 0.
|
|
16
|
+
function calibrate(rows, { minPrecision = 0.85 } = {}) {
|
|
17
17
|
let best = null;
|
|
18
18
|
for (let c = 50; c <= 99; c++) {
|
|
19
19
|
for (let m = 0; m <= 90; m += 5) {
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
// Labels System One training prompts with an LLM against the owner's rules (docs/system-one-corpus.md).
|
|
4
4
|
// See docs/system-one-training.md. Labels stay local; only the holdout agreement report may be committed.
|
|
5
5
|
const fs = require('node:fs');
|
|
6
|
+
const os = require('node:os');
|
|
6
7
|
const path = require('node:path');
|
|
7
8
|
const { spawn } = require('node:child_process');
|
|
8
9
|
const { createHash } = require('node:crypto');
|
|
@@ -105,6 +106,32 @@ function commandRunner(model) {
|
|
|
105
106
|
child.stdin.end(prompt);
|
|
106
107
|
});
|
|
107
108
|
}
|
|
109
|
+
// One stateless `codex exec` per batch: prompt on stdin, schema-checked last message in a temp file,
|
|
110
|
+
// read-only sandbox, no session files and no user config (plugins/hooks), so nothing accumulates across batches.
|
|
111
|
+
function codexRunner(model) {
|
|
112
|
+
const base = process.env.HARNESS_S1_LABEL_COMMAND ? JSON.parse(process.env.HARNESS_S1_LABEL_COMMAND) : ['codex'];
|
|
113
|
+
const work = fs.mkdtempSync(path.join(os.tmpdir(), 'harness-s1-codex-'));
|
|
114
|
+
const schemaFile = path.join(work, 'schema.json');
|
|
115
|
+
fs.writeFileSync(schemaFile, SCHEMA);
|
|
116
|
+
let n = 0;
|
|
117
|
+
return prompt => new Promise((resolve, reject) => {
|
|
118
|
+
const outFile = path.join(work, `reply-${process.pid}-${n++}.json`);
|
|
119
|
+
const args = ['exec', '--model', model, '-c', 'model_reasoning_effort=medium', '--sandbox', 'read-only', '--skip-git-repo-check',
|
|
120
|
+
'--ephemeral', '--ignore-user-config', '--output-schema', schemaFile, '-o', outFile, '-C', work, '-'];
|
|
121
|
+
const child = spawn(base[0], [...base.slice(1), ...args], { stdio: ['pipe', 'ignore', 'ignore'], windowsHide: true,
|
|
122
|
+
shell: process.platform === 'win32' && !process.env.HARNESS_S1_LABEL_COMMAND });
|
|
123
|
+
const timer = setTimeout(() => child.kill(), 600000);
|
|
124
|
+
child.on('error', err => { clearTimeout(timer); reject(err); });
|
|
125
|
+
child.on('close', code => {
|
|
126
|
+
clearTimeout(timer);
|
|
127
|
+
let reply = null;
|
|
128
|
+
try { reply = JSON.parse(fs.readFileSync(outFile, 'utf8')); } catch (_) { reject(new Error(`codex-exit-${code}: no reply`)); return; }
|
|
129
|
+
try { fs.unlinkSync(outFile); } catch (_) { /* temp file */ }
|
|
130
|
+
resolve(reply);
|
|
131
|
+
});
|
|
132
|
+
child.stdin.end(prompt);
|
|
133
|
+
});
|
|
134
|
+
}
|
|
108
135
|
function outsideRepo(file) {
|
|
109
136
|
const rel = path.relative(REPO, path.resolve(file));
|
|
110
137
|
if (!rel.startsWith('..') && !path.isAbsolute(rel)) throw new Error('refusing to write labels inside the repository');
|
|
@@ -113,10 +140,12 @@ function outsideRepo(file) {
|
|
|
113
140
|
async function main(argv) {
|
|
114
141
|
const [op, ...rest] = argv;
|
|
115
142
|
const opt = (name, fallback) => { const i = rest.indexOf(name); return i >= 0 ? rest[i + 1] : fallback; };
|
|
116
|
-
const
|
|
143
|
+
const engine = opt('--engine', 'claude');
|
|
144
|
+
if (!['claude', 'codex'].includes(engine)) throw new Error('--engine must be claude or codex');
|
|
145
|
+
const model = opt('--model', engine === 'codex' ? 'gpt-5.6-luna' : 'sonnet');
|
|
117
146
|
const rules = rulesFromDoc(fs.readFileSync(path.join(REPO, 'docs', 'system-one-corpus.md'), 'utf8'));
|
|
118
|
-
const labeler = { model, rulesSha256: sha(rules).slice(0, 16) };
|
|
119
|
-
const run = commandRunner(model);
|
|
147
|
+
const labeler = { model, rulesSha256: sha(rules).slice(0, 16), ...(engine === 'codex' ? { engine } : {}) };
|
|
148
|
+
const run = engine === 'codex' ? codexRunner(model) : commandRunner(model);
|
|
120
149
|
const concurrency = Number(opt('--concurrency', '4')); const batchSize = Number(opt('--batch', '100'));
|
|
121
150
|
if (op === 'label') {
|
|
122
151
|
const input = opt('--in'); const out = opt('--out');
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Train the System One ngram tier scorer (docs/system-one-training.md, docs/system-one-routing.md "N-gram provider").
|
|
3
|
+
|
|
4
|
+
Featurization is stdlib-only and must match harness-everything/scripts/system-one/ngram.js exactly
|
|
5
|
+
(ci/mechanism-system-one-ngram.test.js compares them). torch is imported only inside train() for the optimizer.
|
|
6
|
+
"""
|
|
7
|
+
import argparse
|
|
8
|
+
import hashlib
|
|
9
|
+
import json
|
|
10
|
+
import math
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
import struct
|
|
13
|
+
import sys
|
|
14
|
+
|
|
15
|
+
sys.dont_write_bytecode = True
|
|
16
|
+
REPO = Path(__file__).resolve().parents[1]
|
|
17
|
+
DEFAULT_HOLDOUT = REPO / 'benchmarks' / 'fixtures' / 'system-one-holdout.json'
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def fnv1a32(text):
|
|
21
|
+
h = 0x811c9dc5
|
|
22
|
+
for byte in text.encode('utf-8'):
|
|
23
|
+
h ^= byte
|
|
24
|
+
h = (h * 0x01000193) & 0xFFFFFFFF
|
|
25
|
+
return h
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def featurize(text, nmax, dim):
|
|
29
|
+
"""bucket -> weight: log(1 + count) per code-point n-gram, one length bucket, L2-normalized."""
|
|
30
|
+
t = ' '.join(text.lower().split())
|
|
31
|
+
counts = {}
|
|
32
|
+
for n in range(1, nmax + 1):
|
|
33
|
+
for i in range(len(t) - n + 1):
|
|
34
|
+
gram = t[i:i + n]
|
|
35
|
+
if not gram.strip():
|
|
36
|
+
continue
|
|
37
|
+
b = fnv1a32(f'{n}:{gram}') % dim
|
|
38
|
+
counts[b] = counts.get(b, 0) + 1
|
|
39
|
+
k = min(8, int(math.floor(math.log2(len(t.encode('utf-8')) + 1))))
|
|
40
|
+
counts[fnv1a32(f'len:{k}') % dim] = 1
|
|
41
|
+
feats = {b: math.log1p(c) for b, c in counts.items()}
|
|
42
|
+
norm = math.sqrt(sum(v * v for v in feats.values()))
|
|
43
|
+
return {b: v / norm for b, v in feats.items()}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def load_jsonl(path):
|
|
47
|
+
return [json.loads(line) for line in Path(path).read_text(encoding='utf-8').splitlines() if line.strip()]
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def sha256_file(path):
|
|
51
|
+
return hashlib.sha256(Path(path).read_bytes()).hexdigest()
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def train(args):
|
|
55
|
+
import torch
|
|
56
|
+
|
|
57
|
+
torch.manual_seed(args.seed)
|
|
58
|
+
data = Path(args.data_dir)
|
|
59
|
+
corpus = json.loads(Path(args.holdout).read_text(encoding='utf-8'))
|
|
60
|
+
catalog = [o['id'] for o in corpus['cases'][0]['request']['options']]
|
|
61
|
+
gold = {r['id']: r['gold'] for r in load_jsonl(data / 'labels.jsonl')}
|
|
62
|
+
overrides = data / 'owner-overrides.jsonl'
|
|
63
|
+
if overrides.exists():
|
|
64
|
+
gold.update({r['id']: r['gold'] for r in load_jsonl(overrides)})
|
|
65
|
+
excluded = data / 'owner-excluded.jsonl'
|
|
66
|
+
skip = {r['id'] for r in load_jsonl(excluded)} if excluded.exists() else set()
|
|
67
|
+
rows = [p for p in load_jsonl(data / 'prompts.jsonl') if p['id'] in gold and p['id'] not in skip]
|
|
68
|
+
index = lambda g: catalog.index('unclassified' if g is None else g)
|
|
69
|
+
split = {name: [r for r in rows if r['split'] == name] for name in ('train', 'validation')}
|
|
70
|
+
|
|
71
|
+
def matrix(items):
|
|
72
|
+
ii, jj, vv = [], [], []
|
|
73
|
+
for r, item in enumerate(items):
|
|
74
|
+
for b, v in featurize(item['text'], args.nmax, args.dim).items():
|
|
75
|
+
ii.append(r); jj.append(b); vv.append(v)
|
|
76
|
+
return torch.sparse_coo_tensor([ii, jj], vv, (len(items), args.dim), dtype=torch.float32).coalesce()
|
|
77
|
+
|
|
78
|
+
x_train, x_val = matrix(split['train']), matrix(split['validation'])
|
|
79
|
+
y_train = torch.tensor([index(gold[r['id']]) for r in split['train']])
|
|
80
|
+
counts = torch.bincount(y_train, minlength=len(catalog)).float()
|
|
81
|
+
inverse = torch.where(counts > 0, counts.sum() / (len(catalog) * counts.clamp_min(1)), torch.zeros_like(counts))
|
|
82
|
+
weight = {'none': None, 'sqrt': inverse.sqrt(), 'full': inverse}[args.balance]
|
|
83
|
+
W = torch.zeros(args.dim, len(catalog), requires_grad=True)
|
|
84
|
+
bias = torch.zeros(len(catalog), requires_grad=True)
|
|
85
|
+
optimizer = torch.optim.Adam([W, bias], lr=args.lr)
|
|
86
|
+
for _ in range(args.epochs):
|
|
87
|
+
optimizer.zero_grad()
|
|
88
|
+
loss = torch.nn.functional.cross_entropy(torch.sparse.mm(x_train, W) + bias, y_train, weight=weight) + args.weight_decay * (W ** 2).sum()
|
|
89
|
+
loss.backward()
|
|
90
|
+
optimizer.step()
|
|
91
|
+
with torch.no_grad():
|
|
92
|
+
probs = torch.softmax(torch.sparse.mm(x_val, W) + bias, 1)
|
|
93
|
+
out = Path(args.out)
|
|
94
|
+
out.mkdir(parents=True, exist_ok=True)
|
|
95
|
+
weights = W.detach().contiguous().view(-1).tolist()
|
|
96
|
+
(out / 'harness-routing-v1.bin').write_bytes(struct.pack(f'<{len(weights)}f', *weights))
|
|
97
|
+
datasets = {name: sha256_file(data / name) for name in ('prompts.jsonl', 'labels.jsonl')}
|
|
98
|
+
if overrides.exists():
|
|
99
|
+
datasets['owner-overrides.jsonl'] = sha256_file(overrides)
|
|
100
|
+
sidecar = {'format': 'harness-ngram', 'formatVersion': 1, 'dim': args.dim, 'nmax': args.nmax, 'hash': 'fnv1a32', 'catalog': catalog,
|
|
101
|
+
'bias': [float(v) for v in bias.detach().tolist()],
|
|
102
|
+
'metadata': {'domain': 'harness-routing-v1', 'balance': args.balance, 'weightDecay': args.weight_decay, 'epochs': args.epochs,
|
|
103
|
+
'seed': args.seed, 'datasets': datasets, 'counts': {k: len(v) for k, v in split.items()}}}
|
|
104
|
+
(out / 'harness-routing-v1.json').write_text(json.dumps(sidecar), encoding='utf-8')
|
|
105
|
+
with (out / 'val-scores.jsonl').open('w', encoding='utf-8') as fh:
|
|
106
|
+
for r, p in zip(split['validation'], probs.tolist()):
|
|
107
|
+
fh.write(json.dumps({'id': r['id'], 'gold': gold[r['id']], 'probs': p}) + '\n')
|
|
108
|
+
y_val = torch.tensor([index(gold[r['id']]) for r in split['validation']])
|
|
109
|
+
accuracy = (probs.argmax(1) == y_val).float().mean().item() if len(y_val) else 0.0
|
|
110
|
+
print(json.dumps({'counts': sidecar['metadata']['counts'], 'validationAccuracy': accuracy}))
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def main(argv=None):
|
|
114
|
+
parser = argparse.ArgumentParser(description=__doc__)
|
|
115
|
+
parser.add_argument('--data-dir', required=True)
|
|
116
|
+
parser.add_argument('--out', required=True)
|
|
117
|
+
parser.add_argument('--holdout', default=str(DEFAULT_HOLDOUT), help='source of the fixed catalog only; holdout rows are never trained on')
|
|
118
|
+
parser.add_argument('--dim', type=int, default=1 << 16)
|
|
119
|
+
parser.add_argument('--nmax', type=int, default=3)
|
|
120
|
+
parser.add_argument('--balance', choices=['none', 'sqrt', 'full'], default='sqrt')
|
|
121
|
+
parser.add_argument('--weight-decay', type=float, default=1e-4)
|
|
122
|
+
parser.add_argument('--epochs', type=int, default=60)
|
|
123
|
+
parser.add_argument('--lr', type=float, default=0.01)
|
|
124
|
+
parser.add_argument('--seed', type=int, default=7)
|
|
125
|
+
train(parser.parse_args(argv))
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
if __name__ == '__main__':
|
|
129
|
+
main()
|
|
@@ -50,6 +50,16 @@ def join(prompts, labels, overrides):
|
|
|
50
50
|
return [{'id': p['id'], 'split': p['split'], 'text': p['text'], 'gold': gold[p['id']]} for p in prompts if p['id'] in gold]
|
|
51
51
|
|
|
52
52
|
|
|
53
|
+
def class_weights(label_indices, num_classes):
|
|
54
|
+
"""Inverse-frequency weights that average to 1 over the examples; absent classes get 0."""
|
|
55
|
+
counts = [0] * num_classes
|
|
56
|
+
for i in label_indices:
|
|
57
|
+
counts[i] += 1
|
|
58
|
+
present = sum(1 for c in counts if c)
|
|
59
|
+
total = len(label_indices)
|
|
60
|
+
return [total / (present * c) if c else 0.0 for c in counts]
|
|
61
|
+
|
|
62
|
+
|
|
53
63
|
def make_batches(lengths, token_budget):
|
|
54
64
|
"""Length-bucketed batches: each batch's size times its longest item stays within the budget."""
|
|
55
65
|
order = sorted(range(len(lengths)), key=lambda i: (lengths[i], i))
|
|
@@ -94,6 +104,8 @@ def train(args):
|
|
|
94
104
|
train_batches = make_batches(lengths(split['train']), args.token_budget)
|
|
95
105
|
val_batches = make_batches(lengths(split['validation']), args.token_budget)
|
|
96
106
|
optimizer = torch.optim.AdamW(model.parameters(), lr=args.lr, weight_decay=0.01)
|
|
107
|
+
# Class balance counters the tier2-heavy labels; validation NLL stays unweighted so epochs remain comparable.
|
|
108
|
+
weight = torch.tensor(class_weights([e.label for e in train_x], len(catalog)), dtype=torch.float) if args.balance else None
|
|
97
109
|
|
|
98
110
|
def evaluate():
|
|
99
111
|
model.eval()
|
|
@@ -118,7 +130,7 @@ def train(args):
|
|
|
118
130
|
total = 0.0
|
|
119
131
|
for b in order:
|
|
120
132
|
tensors = collator([train_x[i] for i in train_batches[b]])
|
|
121
|
-
loss = torch.nn.functional.cross_entropy(model(tensors), tensors['labels'])
|
|
133
|
+
loss = torch.nn.functional.cross_entropy(model(tensors), tensors['labels'], weight=weight)
|
|
122
134
|
optimizer.zero_grad()
|
|
123
135
|
loss.backward()
|
|
124
136
|
torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)
|
|
@@ -161,6 +173,7 @@ def main(argv=None):
|
|
|
161
173
|
parser.add_argument('--threads', type=int, default=4)
|
|
162
174
|
parser.add_argument('--context-tokens', type=int, default=1024)
|
|
163
175
|
parser.add_argument('--token-budget', type=int, default=16384)
|
|
176
|
+
parser.add_argument('--balance', action='store_true', help='inverse-frequency class weights in the training loss')
|
|
164
177
|
train(parser.parse_args(argv))
|
|
165
178
|
|
|
166
179
|
|