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.
Files changed (41) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +12 -0
  4. package/benchmarks/fixtures/system-one-holdout-reviews.json +18 -18
  5. package/benchmarks/fixtures/system-one-holdout.json +9 -9
  6. package/benchmarks/results/system-one/harness-routing-v1-cpu-2026-09-24/README.md +75 -0
  7. package/benchmarks/results/system-one/harness-routing-v1-cpu-2026-09-24/report.json +10832 -0
  8. package/benchmarks/results/system-one/harness-routing-v1-ngram-2026-09-24/README.md +72 -0
  9. package/benchmarks/results/system-one/harness-routing-v1-ngram-2026-09-24/report.json +10817 -0
  10. package/benchmarks/results/system-one/harness-routing-v3-ngram-2026-09-24/README.md +63 -0
  11. package/benchmarks/results/system-one/harness-routing-v3-ngram-2026-09-24/report.json +10817 -0
  12. package/benchmarks/results/system-one/labeler-holdout-check-2026-09-24/report.json +1104 -0
  13. package/benchmarks/results/system-one/labeler-holdout-check-codex-2026-09-24/report.json +1104 -0
  14. package/benchmarks/results/system-one/labeler-holdout-check-codex-tier3-2026-09-24/report.json +1104 -0
  15. package/ci/mechanism-system-one-evaluation.test.js +17 -0
  16. package/ci/mechanism-system-one-label.test.js +27 -0
  17. package/ci/mechanism-system-one-ngram.test.js +161 -0
  18. package/ci/mechanism-system-one-train.test.js +12 -0
  19. package/ci/system-one-ngram-parity.py +19 -0
  20. package/ci/system-one-train-test.py +6 -0
  21. package/docs/system-one-corpus.md +31 -3
  22. package/docs/system-one-routing.md +84 -2
  23. package/docs/system-one-training.md +14 -2
  24. package/harness-everything/SKILL.md +1 -1
  25. package/harness-everything/scripts/system-one/evaluate.js +3 -2
  26. package/harness-everything/scripts/system-one/ngram.js +84 -0
  27. package/harness-everything/scripts/system-one/provider.js +15 -5
  28. package/opencode-plugin/plugin.json +1 -1
  29. package/package.json +1 -1
  30. package/plugins/harness-everything/.codex-plugin/plugin.json +1 -1
  31. package/plugins/harness-everything/plugin.json +1 -1
  32. package/plugins/harness-everything/skills/harness-everything/SKILL.md +1 -1
  33. package/plugins/harness-everything/skills/harness-everything/scripts/system-one/evaluate.js +3 -2
  34. package/plugins/harness-everything/skills/harness-everything/scripts/system-one/ngram.js +84 -0
  35. package/plugins/harness-everything/skills/harness-everything/scripts/system-one/provider.js +15 -5
  36. package/sbom.cdx.json +7 -7
  37. package/scripts/evaluate-system-one.js +16 -9
  38. package/scripts/system-one-calibrate.js +1 -1
  39. package/scripts/system-one-label.js +32 -3
  40. package/scripts/system-one-train-ngram.py +129 -0
  41. package/scripts/system-one-train.py +14 -1
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "harness-enforcement",
3
3
  "description": "Repository inventory for the opencode enforcement plugin and its standalone helper",
4
- "version": "0.28.0",
4
+ "version": "0.29.0",
5
5
  "runtime": "index.mjs",
6
6
  "hooks": {
7
7
  "verify": "hooks/verify.js"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "harness-everything",
3
- "version": "0.28.0",
3
+ "version": "0.29.0",
4
4
  "description": "Harness OS: An Orchestrated Agent Operating System for AI-driven Development",
5
5
  "main": "harness-everything/scripts/bootstrap.js",
6
6
  "bin": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "harness-everything",
3
- "version": "0.28.0",
3
+ "version": "0.29.0",
4
4
  "description": "Invariant-first engineering harness for routing, verification, and failure recovery while preserving agent autonomy.",
5
5
  "author": {
6
6
  "name": "Miya Daniel",
@@ -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.28.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",
@@ -4,7 +4,7 @@ description: "Route software/project work through Harness: classify tier/topolog
4
4
  license: Apache-2.0
5
5
  metadata:
6
6
  author: Miya Daniel
7
- version: 0.26.0
7
+ version: 0.29.0
8
8
  ---
9
9
 
10
10
  # Harness Everything
@@ -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.98,
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
- const required = ['schemaVersion', 'python', 'checkpoint', 'weightsSha256', 'configSha256', 'modelId', 'revision', 'domain'];
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
- || ['python', 'modelId', 'revision', 'domain'].some(k => typeof m[k] !== 'string' || !m[k].trim() || m[k].length > 4096 || m[k].includes('\0'))
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:a9471ff7-cd1e-58b8-b661-a6231462bdd7",
5
+ "serialNumber": "urn:uuid:03c78df6-955e-5903-b3d9-620c6be8e2d4",
6
6
  "version": 1,
7
7
  "metadata": {
8
- "timestamp": "2026-09-27T17:31:25.591Z",
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.28.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.28.0",
18
+ "bom-ref": "pkg:npm/harness-everything@0.29.0",
19
19
  "name": "harness-everything",
20
- "version": "0.28.0",
21
- "purl": "pkg:npm/harness-everything@0.28.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.28.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, so every sample is warm; one-shot samples are cold.
17
- const warm = config?.transport === 'resident';
18
- const wasRunning = warm && resident.status(config, manifest).running;
19
- const ready = warm && resident.ensureReady(config, manifest, 60000);
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 (warm && !wasRunning) resident.stop(config, manifest);
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
- const source = provenance(manifest);
51
- return { ...evaluate(corpus, records, source), evidence: { kind: warm ? 'offline-resident' : 'offline-one-shot', artifact, source,
52
- residentReady: warm ? ready : null,
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.98 } = {}) {
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 model = opt('--model', 'sonnet');
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