harness-everything 0.23.0 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +13 -0
  4. package/benchmarks/results/system-one/labeler-holdout-check-2026-09-23/README.md +55 -0
  5. package/benchmarks/results/system-one/labeler-holdout-check-2026-09-23/report.json +1104 -0
  6. package/ci/fixtures/system-one-resident-stub.py +3 -0
  7. package/ci/mechanism-system-one-collect.test.js +129 -0
  8. package/ci/mechanism-system-one-label.test.js +101 -0
  9. package/ci/mechanism-system-one-resident.test.js +36 -2
  10. package/ci/mechanism-system-one-router.test.js +13 -0
  11. package/ci/mechanism-system-one-train.test.js +82 -0
  12. package/ci/system-one-train-test.py +55 -0
  13. package/docs/system-one-routing.md +8 -1
  14. package/docs/system-one-training.md +121 -0
  15. package/harness-everything/SKILL.md +1 -1
  16. package/harness-everything/scripts/system-one/provider.js +12 -5
  17. package/harness-everything/scripts/system-one/router.js +1 -1
  18. package/opencode-plugin/plugin.json +1 -1
  19. package/package.json +1 -1
  20. package/plugins/harness-everything/.codex-plugin/plugin.json +1 -1
  21. package/plugins/harness-everything/plugin.json +1 -1
  22. package/plugins/harness-everything/skills/harness-everything/SKILL.md +1 -1
  23. package/plugins/harness-everything/skills/harness-everything/scripts/system-one/provider.js +12 -5
  24. package/plugins/harness-everything/skills/harness-everything/scripts/system-one/router.js +1 -1
  25. package/sbom.cdx.json +7 -7
  26. package/scripts/evaluate-system-one.js +1 -1
  27. package/scripts/system-one-calibrate.js +44 -0
  28. package/scripts/system-one-collect.js +196 -0
  29. package/scripts/system-one-label.js +144 -0
  30. package/scripts/system-one-train.py +168 -0
@@ -18,6 +18,9 @@ def factory(weights, manifest):
18
18
  def score(request):
19
19
  if manifest['modelId'] == 'stub-slow':
20
20
  time.sleep(3)
21
+ if manifest['modelId'] == 'stub-soft':
22
+ rest = 0.3 / (len(request['options']) - 1)
23
+ return [0.7] + [rest] * (len(request['options']) - 1)
21
24
  return [1.0] + [0.0] * (len(request['options']) - 1)
22
25
  return score, {'context_tokens': 224, 'option_tokens': 96}
23
26
 
@@ -0,0 +1,129 @@
1
+ 'use strict';
2
+ const { test } = require('node:test');
3
+ const assert = require('node:assert/strict');
4
+ const fs = require('node:fs');
5
+ const os = require('node:os');
6
+ const path = require('node:path');
7
+ const { spawnSync } = require('node:child_process');
8
+ const collect = require('../scripts/system-one-collect');
9
+ const root = path.resolve(__dirname, '..');
10
+ const jsonl = rows => rows.map(r => JSON.stringify(r)).join('\n');
11
+
12
+ // A fake home with one history file per source; each holds user text plus records that must be ignored.
13
+ function fakeHome() {
14
+ const home = fs.mkdtempSync(path.join(os.tmpdir(), 'harness-s1-collect-'));
15
+ const appdata = path.join(home, 'AppData', 'Roaming');
16
+ const write = (rel, body) => { const p = path.join(home, rel); fs.mkdirSync(path.dirname(p), { recursive: true }); fs.writeFileSync(p, body); };
17
+ write('.claude/projects/p1/s-claude.jsonl', jsonl([
18
+ { type: 'user', message: { content: 'fix the typo in README' } },
19
+ { type: 'user', message: { content: [{ type: 'text', text: 'commit all changes' }] } },
20
+ { type: 'user', isMeta: true, message: { content: 'meta text must be skipped' } },
21
+ { type: 'user', isSidechain: true, message: { content: 'sidechain text must be skipped' } },
22
+ { type: 'user', message: { content: [{ type: 'tool_result', tool_use_id: 'x', content: 'tool output must be skipped' }] } },
23
+ { type: 'user', message: { content: '<system-reminder>injected</system-reminder>' } },
24
+ { type: 'user', message: { content: '<command-name>/compact</command-name>' } },
25
+ { type: 'assistant', message: { content: 'assistant text must be skipped' } },
26
+ ]));
27
+ write('.codex/sessions/2026/09/01/rollout-a.jsonl', jsonl([
28
+ { type: 'response_item', payload: { type: 'message', role: 'user', content: [{ type: 'input_text', text: '<environment_context>cwd</environment_context>' }] } },
29
+ { type: 'response_item', payload: { type: 'message', role: 'user', content: [{ type: 'input_text', text: 'duplicate of the event message' }] } },
30
+ { type: 'event_msg', payload: { type: 'user_message', message: 'add a --verbose flag with tests' } },
31
+ ]));
32
+ write('.codex/sessions/2026/09/02/rollout-b.jsonl', jsonl([
33
+ { type: 'response_item', payload: { type: 'message', role: 'user', content: [{ type: 'input_text', text: '<user_instructions>agents</user_instructions>' }] } },
34
+ { type: 'response_item', payload: { type: 'message', role: 'user', content: [{ type: 'input_text', text: 'older session without event messages' }] } },
35
+ ]));
36
+ write('.copilot/session-state/c1/events.jsonl', jsonl([
37
+ { type: 'system.message', data: { content: 'system prompt must be skipped' } },
38
+ { type: 'user.message', data: { content: 'run npm test and report failures' } },
39
+ ]));
40
+ write('AppData/Roaming/Code/User/workspaceStorage/w1/chatSessions/old.json', JSON.stringify({
41
+ requests: [{ message: { text: '把 parseCfg 改名成 parseConfig' } }, { message: { text: '' } }] }));
42
+ write('AppData/Roaming/Code/User/workspaceStorage/w1/chatSessions/new.jsonl', jsonl([
43
+ { kind: 0, v: { sessionId: 's', requests: [{ message: { text: '整個 repo 遷移到 ESM' } }] } },
44
+ { kind: 2, k: ['requests'], v: [{ message: { text: '繼續' } }] },
45
+ { kind: 2, k: ['requests', 0, 'response'], v: [{ value: 'response text must be skipped' }] },
46
+ { kind: 1, k: ['requests', 0, 'result'], v: { metadata: { renderedUserMessage: 'rendered prompt must be skipped' } } },
47
+ ]));
48
+ write('AppData/Roaming/Code/User/globalStorage/emptyWindowChatSessions/e.jsonl', jsonl([
49
+ { kind: 0, v: { requests: [{ message: { text: 'explain the backoff in retry.go' } }] } },
50
+ ]));
51
+ return { home, appdata };
52
+ }
53
+ const texts = rows => rows.map(r => r.text).sort();
54
+
55
+ test('S1-C101 each source yields only owner-typed text', () => {
56
+ const { home, appdata } = fakeHome();
57
+ try {
58
+ const rows = collect.readSources({ home, appdata });
59
+ assert.deepEqual(texts(rows), texts([
60
+ { text: 'fix the typo in README' }, { text: 'commit all changes' }, { text: 'add a --verbose flag with tests' },
61
+ { text: 'older session without event messages' }, { text: 'run npm test and report failures' },
62
+ { text: '把 parseCfg 改名成 parseConfig' }, { text: '整個 repo 遷移到 ESM' }, { text: '繼續' }, { text: 'explain the backoff in retry.go' },
63
+ ]));
64
+ const bySource = Object.fromEntries(['claude', 'codex', 'copilot-cli', 'vscode'].map(s => [s, rows.filter(r => r.source === s).length]));
65
+ assert.deepEqual(bySource, { claude: 2, codex: 2, 'copilot-cli': 1, vscode: 4 });
66
+ assert.ok(rows.every(r => typeof r.family === 'string' && r.family.length > 0));
67
+ const claude = rows.filter(r => r.source === 'claude');
68
+ assert.equal(new Set(claude.map(r => r.family)).size, 1, 'one session file is one family');
69
+ } finally { fs.rmSync(home, { recursive: true, force: true }); }
70
+ });
71
+
72
+ test('S1-C102 filters, redaction and deduplication', () => {
73
+ assert.equal(collect.keep('go'), true);
74
+ assert.equal(collect.keep('x'.repeat(1024)), true);
75
+ assert.equal(collect.keep('x'.repeat(1025)), false);
76
+ assert.equal(collect.keep('中'.repeat(342)), false, '1026 UTF-8 bytes');
77
+ assert.equal(collect.keep('/compact'), false);
78
+ assert.equal(collect.keep('This session is being continued from a previous conversation that ran out of context.'), false);
79
+ assert.equal(collect.keep(' '), false);
80
+ assert.equal(collect.redact('mail dev.lead@example.com now'), 'mail <email> now');
81
+ assert.equal(collect.redact('open C:\\Users\\alice\\repo\\a.md'), 'open <home>\\repo\\a.md');
82
+ assert.equal(collect.redact('read /home/alice/p and /Users/bob/q'), 'read <home>/p and <home>/q');
83
+ const rows = collect.dedupe([{ text: 'fix it', family: 'a' }, { text: 'fix it', family: 'b' }, { text: 'other', family: 'c' }]);
84
+ assert.deepEqual(rows.map(r => r.family), ['a', 'c']);
85
+ });
86
+
87
+ test('S1-C103 prompts that near-duplicate a holdout prompt are dropped', () => {
88
+ const holdout = ['把 parseCfg 改名成 parseConfig, 只有這個檔案有用到', 'Rebase this branch onto the latest main.'];
89
+ const guard = collect.leakGuard(holdout);
90
+ assert.equal(guard('把 parseCfg 改名成 parseConfig'), true, 'contained, longer than 12 chars');
91
+ assert.equal(guard('rebase this branch onto the latest main'), true, 'normalized near-duplicate');
92
+ assert.equal(guard('add pagination to the users endpoint'), false);
93
+ assert.equal(guard('main'), false, 'short containment does not count');
94
+ assert.ok(collect.jaccard('abcdef', 'abcdef') === 1 && collect.jaccard('abc', 'xyz') === 0);
95
+ });
96
+
97
+ test('S1-C104 splits are stable per family and near 15% validation', () => {
98
+ assert.equal(collect.splitFor('family-a'), collect.splitFor('family-a'));
99
+ const families = Array.from({ length: 2000 }, (_, i) => `session-${i}`);
100
+ const share = families.filter(f => collect.splitFor(f) === 'validation').length / families.length;
101
+ assert.ok(share > 0.12 && share < 0.18, String(share));
102
+ assert.ok(families.every(f => ['train', 'validation'].includes(collect.splitFor(f))));
103
+ });
104
+
105
+ test('S1-C105 CLI writes a deterministic local dataset outside the repository', () => {
106
+ const { home, appdata } = fakeHome();
107
+ const out = path.join(home, 'out');
108
+ const holdout = path.join(home, 'holdout.json');
109
+ fs.writeFileSync(holdout, JSON.stringify({ schemaVersion: 1, cases: [{ request: { context: 'Commit all changes.' } }] }));
110
+ try {
111
+ const run = () => spawnSync(process.execPath, [path.join(root, 'scripts/system-one-collect.js'), '--home', home, '--appdata', appdata, '--out', out, '--holdout', holdout],
112
+ { encoding: 'utf8', cwd: root });
113
+ const one = run();
114
+ assert.equal(one.status, 0, one.stderr);
115
+ const first = fs.readFileSync(path.join(out, 'prompts.jsonl'), 'utf8');
116
+ const stats = JSON.parse(one.stdout);
117
+ assert.equal(stats.kept, 8);
118
+ assert.equal(stats.dropped.leak, 1);
119
+ assert.deepEqual(Object.keys(stats.bySource).sort(), ['claude', 'codex', 'copilot-cli', 'vscode']);
120
+ assert.match(stats.sha256, /^[0-9a-f]{64}$/);
121
+ const rows = first.trim().split('\n').map(l => JSON.parse(l));
122
+ assert.ok(rows.every(r => Object.keys(r).sort().join() === 'family,id,source,split,text' && /^[0-9a-f]{16}$/.test(r.id)));
123
+ assert.equal(run().status, 0);
124
+ assert.equal(fs.readFileSync(path.join(out, 'prompts.jsonl'), 'utf8'), first, 'deterministic');
125
+ const inRepo = spawnSync(process.execPath, [path.join(root, 'scripts/system-one-collect.js'), '--home', home, '--appdata', appdata, '--out', path.join(root, 'tmp-dataset'), '--holdout', holdout], { encoding: 'utf8', cwd: root });
126
+ assert.equal(inRepo.status, 1, 'refuses to write the dataset inside the repository');
127
+ assert.equal(fs.existsSync(path.join(root, 'tmp-dataset')), false);
128
+ } finally { fs.rmSync(home, { recursive: true, force: true }); }
129
+ });
@@ -0,0 +1,101 @@
1
+ 'use strict';
2
+ const { test } = require('node:test');
3
+ const assert = require('node:assert/strict');
4
+ const fs = require('node:fs');
5
+ const os = require('node:os');
6
+ const path = require('node:path');
7
+ const { spawnSync } = require('node:child_process');
8
+ const label = require('../scripts/system-one-label');
9
+ const root = path.resolve(__dirname, '..');
10
+ const items = n => Array.from({ length: n }, (_, i) => ({ id: `id${i}`, text: `prompt number ${i}` }));
11
+ const reply = (batch, gold = () => 'tier1') => ({ labels: batch.map((_, i) => ({ i, gold: gold(i) })) });
12
+
13
+ test('S1-L01 the instructions carry the owner rules from the corpus document and every item', () => {
14
+ const rules = label.rulesFromDoc(fs.readFileSync(path.join(root, 'docs/system-one-corpus.md'), 'utf8'));
15
+ assert.match(rules, /\| `tier1` \|/);
16
+ assert.match(rules, /Label the work the prompt would start/);
17
+ assert.doesNotMatch(rules, /## Cases/);
18
+ const prompt = label.buildPrompt(rules, items(3));
19
+ assert.ok(prompt.includes(rules));
20
+ for (let i = 0; i < 3; i++) assert.ok(prompt.includes(JSON.stringify({ i, text: `prompt number ${i}` })));
21
+ assert.throws(() => label.rulesFromDoc('# no gold section'));
22
+ });
23
+
24
+ test('S1-L02 a batch reply must label every index exactly once with a known label', () => {
25
+ const batch = items(3);
26
+ assert.deepEqual(label.validateReply(batch, reply(batch, i => ['tier1', 'null', 'tier3'][i])), ['tier1', null, 'tier3']);
27
+ const bad = [
28
+ { labels: [{ i: 0, gold: 'tier1' }, { i: 1, gold: 'tier1' }] },
29
+ { labels: [...reply(batch).labels, { i: 0, gold: 'tier2' }] },
30
+ { labels: [{ i: 0, gold: 'tier1' }, { i: 1, gold: 'tier1' }, { i: 7, gold: 'tier1' }] },
31
+ { labels: [{ i: 0, gold: 'tier1' }, { i: 1, gold: 'tier4' }, { i: 2, gold: 'tier1' }] },
32
+ { labels: 'nope' }, null,
33
+ ];
34
+ for (const r of bad) assert.equal(label.validateReply(batch, r), null);
35
+ });
36
+
37
+ test('S1-L03 invalid replies are retried once, persistent failures are recorded, never partially accepted, and runs resume', async () => {
38
+ const data = items(250);
39
+ const calls = [];
40
+ let flaky = true;
41
+ const run = async (prompt, batch) => {
42
+ calls.push(batch.length);
43
+ if (batch[0].id === 'id100' && flaky) { flaky = false; return { labels: [] }; }
44
+ if (batch[0].id === 'id200') return { labels: [] };
45
+ return reply(batch, i => (i % 2 ? 'tier2' : 'null'));
46
+ };
47
+ const reasons = [];
48
+ const first = await label.labelAll(data, { run, rules: 'R', batchSize: 100, concurrency: 2, done: new Set(), onFailure: (batch, reason) => reasons.push([batch[0].id, reason]) });
49
+ assert.deepEqual(reasons, [['id100', 'invalid-reply'], ['id200', 'invalid-reply'], ['id200', 'invalid-reply']], 'every failed attempt is reported with its reason');
50
+ const thrown = [];
51
+ await label.labelAll(items(1), { run: async () => { throw new Error('rate limited'); }, rules: 'R', retryDelayMs: 0, onFailure: (b, r) => thrown.push(r) });
52
+ assert.deepEqual(thrown, ['rate limited', 'rate limited']);
53
+ assert.equal(first.labeled.length, 200);
54
+ assert.deepEqual(first.failed.sort(), data.slice(200).map(d => d.id).sort());
55
+ assert.equal(calls.filter(n => n === 100).length, 3, 'the flaky batch ran twice');
56
+ assert.equal(first.labeled.find(r => r.id === 'id101').gold, 'tier2');
57
+ assert.equal(first.labeled.find(r => r.id === 'id100').gold, null);
58
+ calls.length = 0;
59
+ const again = await label.labelAll(data, { run, rules: 'R', batchSize: 100, concurrency: 2, done: new Set(first.labeled.map(r => r.id)) });
60
+ assert.deepEqual(calls, [50, 50], 'only the unlabeled remainder is sent, retried once');
61
+ assert.equal(again.labeled.length, 0);
62
+ });
63
+
64
+ test('S1-L04 holdout agreement reports overall, per-class recall and confusion', () => {
65
+ const gold = [['a', 'tier1'], ['b', 'tier1'], ['c', 'tier2'], ['d', null]];
66
+ const pred = { a: 'tier1', b: 'tier2', c: 'tier2', d: null };
67
+ const r = label.agreement(gold.map(([id, g]) => ({ id, gold: g })), pred);
68
+ assert.equal(r.cases, 4); assert.equal(r.agreement, 0.75);
69
+ assert.deepEqual(r.recall, { tier1: 0.5, tier2: 1, tier3: null, unclassified: 1 });
70
+ assert.equal(r.confusion['tier1->tier2'], 1);
71
+ assert.equal(r.missing, 0);
72
+ assert.equal(label.agreement([{ id: 'x', gold: 'tier1' }], {}).missing, 1);
73
+ });
74
+
75
+ test('S1-L05 CLI labels through the configured command, resumes, checks the holdout and refuses repository output', () => {
76
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'harness-s1-label-'));
77
+ try {
78
+ const fake = path.join(dir, 'fake-claude.js');
79
+ fs.writeFileSync(fake, `let s='';process.stdin.on('data',d=>s+=d).on('end',()=>{const m=[...s.matchAll(/\\{"i":(\\d+),"text"/g)];
80
+ process.stdout.write(JSON.stringify({is_error:false,structured_output:{labels:m.map(x=>({i:Number(x[1]),gold:'tier2'}))}}));});`);
81
+ const input = path.join(dir, 'prompts.jsonl');
82
+ fs.writeFileSync(input, items(5).map(r => JSON.stringify({ ...r, family: 'f', source: 'claude', split: 'train' })).join('\n') + '\n');
83
+ const env = { ...process.env, HARNESS_S1_LABEL_COMMAND: JSON.stringify([process.execPath, fake]) };
84
+ const cli = args => spawnSync(process.execPath, [path.join(root, 'scripts/system-one-label.js'), ...args], { encoding: 'utf8', cwd: root, env });
85
+ const out = path.join(dir, 'labels.jsonl');
86
+ const one = cli(['label', '--in', input, '--out', out]);
87
+ assert.equal(one.status, 0, one.stderr);
88
+ assert.deepEqual(JSON.parse(one.stdout), { labeled: 5, failed: 0, total: 5 });
89
+ const rows = fs.readFileSync(out, 'utf8').trim().split('\n').map(l => JSON.parse(l));
90
+ assert.ok(rows.every(r => r.gold === 'tier2' && r.labeler.model === 'sonnet' && /^[0-9a-f]{16}$/.test(r.labeler.rulesSha256)));
91
+ assert.deepEqual(JSON.parse(cli(['label', '--in', input, '--out', out]).stdout), { labeled: 0, failed: 0, total: 5 });
92
+ const report = path.join(dir, 'check.json');
93
+ const check = cli(['check-holdout', '--out', report]);
94
+ assert.equal(check.status, 0, check.stderr);
95
+ const r = JSON.parse(fs.readFileSync(report, 'utf8'));
96
+ assert.equal(r.cases, 215);
97
+ assert.equal(typeof r.agreement, 'number');
98
+ assert.equal(cli(['label', '--in', input, '--out', path.join(root, 'tmp-labels.jsonl')]).status, 1);
99
+ assert.equal(fs.existsSync(path.join(root, 'tmp-labels.jsonl')), false);
100
+ } finally { fs.rmSync(dir, { recursive: true, force: true }); }
101
+ });
@@ -16,13 +16,13 @@ const request = createRequest('tier', 'fix a typo in README', TIER_OPTIONS);
16
16
  const sha = file => createHash('sha256').update(fs.readFileSync(file)).digest('hex');
17
17
  const sleep = ms => Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
18
18
 
19
- function fixture(modelId = 'stub') {
19
+ function fixture(modelId = 'stub', extra = {}) {
20
20
  const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'harness-s1-resident-'));
21
21
  const checkpoint = path.join(dir, 'model.safetensors');
22
22
  fs.writeFileSync(checkpoint, 'synthetic-not-real-weights');
23
23
  fs.writeFileSync(path.join(dir, 'model.json'), '{}');
24
24
  const manifest = { schemaVersion: 1, python, checkpoint, weightsSha256: sha(checkpoint), configSha256: sha(path.join(dir, 'model.json')),
25
- modelId, revision: 'v1', domain: 'harness-routing-v1', transport: 'resident', idleTimeoutMs: 60000 };
25
+ modelId, revision: 'v1', domain: 'harness-routing-v1', transport: 'resident', idleTimeoutMs: 60000, ...extra };
26
26
  const manifestPath = path.join(dir, 'manifest.json');
27
27
  fs.writeFileSync(manifestPath, JSON.stringify(manifest));
28
28
  const spawns = [];
@@ -294,3 +294,37 @@ test('S1-RS12 the evaluator times the async path: no worker thread per warm scor
294
294
  assert.ok(Number(fs.readFileSync(countFile, 'utf8')) < report.records.length * 2, 'warm scores must not start a worker thread each');
295
295
  } finally { cleanup(f); }
296
296
  });
297
+
298
+ test('S1-RS13 manifest acceptance thresholds are validated, carried by scored results and applied by the evaluator', async () => {
299
+ const acceptance = { minConfidence: 0.6, minMargin: 0.3 };
300
+ const base = fixture();
301
+ try {
302
+ for (const ok of [acceptance, { minConfidence: 0.5, minMargin: 0 }, { minConfidence: 0.99, minMargin: 0.9 }]) assert.equal(provider.validateManifest({ ...base.manifest, acceptance: ok }), true);
303
+ for (const bad of [{ minConfidence: 0.49, minMargin: 0.2 }, { minConfidence: 1, minMargin: 0.2 }, { minConfidence: 0.9, minMargin: 0.91 }, { minConfidence: 0.9 }, { minConfidence: 0.9, minMargin: 0.2, extra: 1 }, { minConfidence: '0.9', minMargin: 0.2 }, null, []]) {
304
+ assert.throws(() => provider.validateManifest({ ...base.manifest, acceptance: bad }), JSON.stringify(bad));
305
+ }
306
+ } finally { cleanup(base); }
307
+ const root = path.resolve(__dirname, '..');
308
+ const corpus = path.join(root, 'benchmarks/fixtures/system-one-routing.json');
309
+ const evaluateWith = f => {
310
+ const output = path.join(f.dir, 'report.json');
311
+ const child = spawnSync(process.execPath, [path.join(root, 'scripts/evaluate-system-one.js'), corpus, f.manifestPath, output], { cwd: root, encoding: 'utf8' });
312
+ assert.equal(child.status, 0, child.stderr);
313
+ return JSON.parse(fs.readFileSync(output, 'utf8')).records.flatMap(r => r.runs).filter(r => r.decision.reason !== 'provider-exit');
314
+ };
315
+ const soft = fixture('stub-soft', { acceptance });
316
+ try {
317
+ assert.equal(resident.ensureReady(soft.manifest, soft.manifestPath, 20000, soft.deps), true);
318
+ const result = provider.score(request, soft.manifestPath);
319
+ assert.equal(result.status, 'scored');
320
+ assert.deepEqual(result.acceptance, acceptance);
321
+ assert.deepEqual((await provider.scoreAsync(request, soft.manifestPath)).acceptance, acceptance);
322
+ assert.ok(evaluateWith(soft).every(r => r.decision.status === 'accepted' && r.decision.selectedId === 'tier1'));
323
+ } finally { cleanup(soft); }
324
+ const strict = fixture('stub-soft');
325
+ try {
326
+ assert.equal(resident.ensureReady(strict.manifest, strict.manifestPath, 20000, strict.deps), true);
327
+ assert.equal(provider.score(request, strict.manifestPath).acceptance, undefined);
328
+ assert.ok(evaluateWith(strict).every(r => r.decision.status === 'abstain' && r.decision.reason === 'low-confidence'));
329
+ } finally { cleanup(strict); }
330
+ });
@@ -99,6 +99,19 @@ test('S1-R05 structural floor: a scorer can raise but never lower a deterministi
99
99
  assert.equal(plan.verification.independent, true);
100
100
  } finally { provider.score = original; console.log = log; if (mode === undefined) delete process.env.HARNESS_SYSTEM_ONE_MODE; else process.env.HARNESS_SYSTEM_ONE_MODE = mode; }
101
101
  });
102
+ test('S1-R07 a scored result with calibrated acceptance thresholds decides with them', () => {
103
+ const env = { HARNESS_SYSTEM_ONE_MODE: 'prefer' };
104
+ const input = { prompt: 'rename tmp to buffer', tier: 'Unclassified' };
105
+ const soft = (acceptance) => req => ({ status: 'scored', ...(acceptance ? { acceptance } : {}), response: { schemaVersion: 1, requestHash: req.requestHash, catalogHash: req.catalogHash,
106
+ model: { id: 'fixture', revision: 'v1', domain: 'harness-routing-v1' }, scores: req.options.map(o => ({ id: o.id, probability: o.id === 'tier2' ? 0.7 : 0.1 })) } });
107
+ const without = selectTier(input, env, soft(null));
108
+ assert.equal(without.diagnostic.reason, 'low-confidence');
109
+ assert.equal(without.tier, input.tier);
110
+ const withThresholds = selectTier(input, env, soft({ minConfidence: 0.6, minMargin: 0.3 }));
111
+ assert.equal(withThresholds.diagnostic.status, 'accepted');
112
+ assert.equal(withThresholds.tier, 'Tier 2 (Standard Task)');
113
+ assert.equal(selectTier(input, env, soft({ minConfidence: 0.6, minMargin: 0.7 })).diagnostic.reason, 'low-margin');
114
+ });
102
115
  test('S1-R06 prescoreTier: off loads nothing; a matching request reuses the async result; mismatch and failure keep sync semantics', async () => {
103
116
  const { prescoreTier } = require('../harness-everything/scripts/system-one/router');
104
117
  const provider = require('../harness-everything/scripts/system-one/provider');
@@ -0,0 +1,82 @@
1
+ 'use strict';
2
+ const { test } = require('node:test');
3
+ const assert = require('node:assert/strict');
4
+ const fs = require('node:fs');
5
+ const os = require('node:os');
6
+ const path = require('node:path');
7
+ const { spawnSync } = require('node:child_process');
8
+ const { calibrate, decideRow } = require('../scripts/system-one-calibrate');
9
+ const root = path.resolve(__dirname, '..');
10
+ const python = process.env.PYTHON || (process.platform === 'win32' ? 'python' : 'python3');
11
+
12
+ test('S1-T01 trainer data handling is exercised without torch', () => {
13
+ const r = spawnSync(python, [path.join(__dirname, 'system-one-train-test.py')], { encoding: 'utf8', env: { ...process.env, PYTHONDONTWRITEBYTECODE: '1' } });
14
+ assert.equal(r.status, 0, r.stdout + r.stderr);
15
+ assert.match(r.stdout, /trainer data tests passed/);
16
+ });
17
+
18
+ const row = (gold, probs) => ({ gold, probs });
19
+ test('S1-T02 a validation row is accepted only above both thresholds and never as unclassified', () => {
20
+ assert.deepEqual(decideRow([0.95, 0.03, 0.01, 0.01], { minConfidence: 0.9, minMargin: 0.2 }), 'tier1');
21
+ assert.equal(decideRow([0.85, 0.1, 0.03, 0.02], { minConfidence: 0.9, minMargin: 0.2 }), null);
22
+ assert.equal(decideRow([0.55, 0.45, 0, 0], { minConfidence: 0.5, minMargin: 0.2 }), null);
23
+ assert.equal(decideRow([0.01, 0.01, 0.01, 0.97], { minConfidence: 0.5, minMargin: 0 }), null);
24
+ });
25
+
26
+ test('S1-T03 calibration maximizes coverage subject to accepted precision on validation only', () => {
27
+ const rows = [
28
+ ...Array.from({ length: 90 }, () => row('tier1', [0.97, 0.01, 0.01, 0.01])),
29
+ ...Array.from({ length: 5 }, () => row('tier2', [0.8, 0.15, 0.03, 0.02])),
30
+ ...Array.from({ length: 5 }, () => row('tier2', [0.1, 0.85, 0.03, 0.02])),
31
+ ];
32
+ const c = calibrate(rows, { minPrecision: 0.98 });
33
+ assert.ok(c.precision >= 0.98, JSON.stringify(c));
34
+ assert.equal(c.coverage, 0.95, JSON.stringify(c));
35
+ // Either threshold may separate the rows; the chosen pair must reject the wrong ones and keep the right ones.
36
+ assert.equal(decideRow([0.8, 0.15, 0.03, 0.02], c), null, JSON.stringify(c));
37
+ assert.equal(decideRow([0.1, 0.85, 0.03, 0.02], c), 'tier2', JSON.stringify(c));
38
+ const none = calibrate([row('tier1', [0.3, 0.7, 0, 0])], { minPrecision: 0.98 });
39
+ assert.equal(none.feasible, false);
40
+ assert.equal(none.coverage, 0);
41
+ assert.deepEqual(calibrate(rows, { minPrecision: 0.98 }), c, 'deterministic');
42
+ });
43
+
44
+ test('S1-T04 calibration CLI reads validation scores and writes thresholds', () => {
45
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'harness-s1-cal-'));
46
+ try {
47
+ const input = path.join(dir, 'val-scores.jsonl');
48
+ fs.writeFileSync(input, Array.from({ length: 50 }, (_, i) => JSON.stringify({ id: `v${i}`, gold: 'tier2', probs: [0.02, 0.95, 0.02, 0.01] })).join('\n') + '\n');
49
+ const out = path.join(dir, 'calibration.json');
50
+ const r = spawnSync(process.execPath, [path.join(root, 'scripts/system-one-calibrate.js'), input, out], { encoding: 'utf8' });
51
+ assert.equal(r.status, 0, r.stderr);
52
+ const c = JSON.parse(fs.readFileSync(out, 'utf8'));
53
+ assert.equal(c.feasible, true); assert.equal(c.coverage, 1); assert.equal(c.rows, 50);
54
+ assert.equal(spawnSync(process.execPath, [path.join(root, 'scripts/system-one-calibrate.js')], { encoding: 'utf8' }).status, 1);
55
+ } finally { fs.rmSync(dir, { recursive: true, force: true }); }
56
+ });
57
+
58
+ test('S1-T05 a real tiny training run produces a checkpoint the adapter loads (skipped without torch)', t => {
59
+ const probe = spawnSync(python, ['-c', 'import torch, cua_s1'], { encoding: 'utf8' });
60
+ if (probe.status !== 0) { t.skip('torch/cua_s1 not installed; mechanism tests above still run'); return; }
61
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'harness-s1-train-'));
62
+ try {
63
+ const data = path.join(dir, 'data'); fs.mkdirSync(data);
64
+ const texts = ['commit all changes', 'push and open a pr', 'add a flag with tests', 'migrate every service', 'go', 'yes'];
65
+ const golds = ['tier1', 'tier1', 'tier3', 'tier3', null, null];
66
+ const prompts = []; const labels = [];
67
+ for (let k = 0; k < 8; k++) texts.forEach((t, i) => { const id = `p${k}-${i}`; prompts.push({ id, family: `f${k}`, source: 'claude', split: k < 6 ? 'train' : 'validation', text: `${t} ${k}` }); labels.push({ id, gold: golds[i] }); });
68
+ fs.writeFileSync(path.join(data, 'prompts.jsonl'), prompts.map(p => JSON.stringify(p)).join('\n') + '\n');
69
+ fs.writeFileSync(path.join(data, 'labels.jsonl'), labels.map(p => JSON.stringify(p)).join('\n') + '\n');
70
+ const out = path.join(dir, 'model');
71
+ const r = spawnSync(python, [path.join(root, 'scripts/system-one-train.py'), '--data-dir', data, '--out', out, '--epochs', '2', '--context-tokens', '64'], { encoding: 'utf8' });
72
+ assert.equal(r.status, 0, r.stdout + r.stderr);
73
+ const report = JSON.parse(fs.readFileSync(path.join(out, 'train-report.json'), 'utf8'));
74
+ assert.equal(report.counts.train, 36); assert.equal(report.counts.validation, 12);
75
+ const scores = fs.readFileSync(path.join(out, 'val-scores.jsonl'), 'utf8').trim().split('\n').map(l => JSON.parse(l));
76
+ assert.equal(scores.length, 12);
77
+ assert.ok(scores.every(s => s.probs.length === 4 && Math.abs(s.probs.reduce((a, b) => a + b, 0) - 1) < 1e-5));
78
+ const load = spawnSync(python, ['-c', `from cua_s1.model import load_checkpoint; m,c,cfg=load_checkpoint(r'${path.join(out, 'harness-routing-v1.safetensors')}','cpu'); print(cfg['context_tokens'])`], { encoding: 'utf8' });
79
+ assert.equal(load.status, 0, load.stderr);
80
+ assert.equal(load.stdout.trim(), '64');
81
+ } finally { fs.rmSync(dir, { recursive: true, force: true }); }
82
+ });
@@ -0,0 +1,55 @@
1
+ """Stdlib-only tests for the System One trainer's data handling (no torch needed)."""
2
+ import importlib.util
3
+ import json
4
+ from pathlib import Path
5
+ import sys
6
+ import tempfile
7
+
8
+ sys.dont_write_bytecode = True
9
+ ROOT = Path(__file__).resolve().parents[1]
10
+ spec = importlib.util.spec_from_file_location('trainer', ROOT / 'scripts' / 'system-one-train.py')
11
+ trainer = importlib.util.module_from_spec(spec)
12
+ spec.loader.exec_module(trainer)
13
+ assert 'torch' not in sys.modules, 'importing the trainer must not import torch'
14
+
15
+ catalog = trainer.catalog_from_holdout(ROOT / 'benchmarks' / 'fixtures' / 'system-one-holdout.json')
16
+ assert [o['id'] for o in catalog] == ['tier1', 'tier2', 'tier3', 'unclassified'], catalog
17
+ assert all(o['text'] for o in catalog)
18
+ assert trainer.label_index('tier2', catalog) == 1
19
+ assert trainer.label_index(None, catalog) == 3
20
+ try:
21
+ trainer.label_index('tier9', catalog)
22
+ raise SystemExit('unknown gold must be rejected')
23
+ except ValueError:
24
+ pass
25
+
26
+ prompts = [
27
+ {'id': 'a', 'family': 'f1', 'source': 'claude', 'split': 'train', 'text': 'commit'},
28
+ {'id': 'b', 'family': 'f2', 'source': 'vscode', 'split': 'validation', 'text': 'fix the parser'},
29
+ {'id': 'c', 'family': 'f3', 'source': 'codex', 'split': 'train', 'text': 'unlabeled prompt'},
30
+ {'id': 'd', 'family': 'f4', 'source': 'codex', 'split': 'train', 'text': 'owner override'},
31
+ ]
32
+ labels = [{'id': 'a', 'gold': 'tier1'}, {'id': 'b', 'gold': None}, {'id': 'd', 'gold': 'tier3'}]
33
+ overrides = [{'id': 'd', 'gold': 'tier2'}]
34
+ examples = trainer.join(prompts, labels, overrides)
35
+ assert [(e['id'], e['split'], e['gold']) for e in examples] == [('a', 'train', 'tier1'), ('b', 'validation', None), ('d', 'train', 'tier2')], examples
36
+ try:
37
+ trainer.join(prompts, labels + [{'id': 'a', 'gold': 'tier2'}], [])
38
+ raise SystemExit('duplicate labels must be rejected')
39
+ except ValueError:
40
+ pass
41
+
42
+ lengths = [10, 1024, 300, 5, 700, 1024, 50] * 20
43
+ batches = trainer.make_batches(lengths, token_budget=4096)
44
+ flat = sorted(i for b in batches for i in b)
45
+ assert flat == list(range(len(lengths))), 'every example exactly once'
46
+ assert all(len(b) * max(lengths[i] for i in b) <= 4096 or len(b) == 1 for b in batches), 'budget respected'
47
+ assert batches == trainer.make_batches(lengths, token_budget=4096), 'deterministic'
48
+
49
+ with tempfile.TemporaryDirectory() as tmp:
50
+ p = Path(tmp) / 'rows.jsonl'
51
+ p.write_text('\n'.join(json.dumps(r) for r in prompts) + '\n', encoding='utf-8')
52
+ assert trainer.load_jsonl(p) == prompts
53
+ assert len(trainer.sha256_file(p)) == 64
54
+
55
+ print('system-one trainer data tests passed')
@@ -41,7 +41,11 @@ never a prompt-supplied executable. No shell or automatic download is used.
41
41
  The manifest is version 1 with `python` (executable), `checkpoint` (absolute
42
42
  `.safetensors` path), `weightsSha256`, `configSha256` (matching `.json` sidecar),
43
43
  `modelId`, `revision`, `domain`, and optional `timeoutMs` (1–10000, default 2000).
44
- All fields are required except the timeout; unknown fields are rejected. Hashes
44
+ All fields are required except the timeout; unknown fields are rejected. An
45
+ optional `acceptance` object holds exactly `minConfidence` (0.5–0.99) and
46
+ `minMargin` (0–0.9). These are the thresholds calibrated on validation for this
47
+ checkpoint. A scored result carries them, and the router and the evaluator pass
48
+ them to `decide`. Without the field the Phase 0 defaults apply. Hashes
45
49
  must be lowercase SHA-256. Revision and domain are artifact-owner declarations,
46
50
  not independently verified quality claims. The known `cua-ai/cua-s1-forms` ID
47
51
  must use domain `forms-v1`. No pickle format or remote URL is accepted.
@@ -279,6 +283,9 @@ unversioned download during a prompt hook.
279
283
  | 3 | Corpus and paired evaluator | Leakage checks, coverage/error metrics, repeatability |
280
284
  | 4 | Harness training and rollout | Real checkpoint, reviewed holdout, measured host results |
281
285
 
286
+ Phase 4 training data, labeling, calibration and release are defined in
287
+ [system-one-training.md](system-one-training.md).
288
+
282
289
  ## Rollout gates
283
290
 
284
291
  Phase 4 requires a separately reviewed, family-disjoint holdout of at least 200
@@ -0,0 +1,121 @@
1
+ # System One training data and weights
2
+
3
+ This document defines how the `harness-routing-v1` tier checkpoint for
4
+ [System One](system-one-routing.md) is trained, calibrated and released
5
+ (issue [#233](https://github.com/dyphn1/Harness-everything/issues/233), Phase 4).
6
+ Gold labels follow [system-one-corpus.md](system-one-corpus.md). The owner-reviewed
7
+ holdout in that document is used only for evaluation. It is never used for training,
8
+ threshold selection or labeler tuning.
9
+
10
+ ## Pipeline
11
+
12
+ 1. **Collect**: copy the owner's own prompts from local assistant histories into a local
13
+ dataset (`scripts/system-one-collect.js`).
14
+ 2. **Label**: an LLM labels each prompt against the owner's rules. The labeler is checked
15
+ once against the holdout, and the owner spot-checks a sample
16
+ (`scripts/system-one-label.js`).
17
+ 3. **Train**: train a fresh `cua_s1` `tinyx` scorer on the train split and select the epoch
18
+ on the validation split.
19
+ 4. **Calibrate**: choose the confidence and margin thresholds on validation.
20
+ 5. **Evaluate**: produce one paired report on the holdout.
21
+ 6. **Release**: publish the weights as a GitHub release asset. The installer pins them by
22
+ SHA-256.
23
+
24
+ ## Sources
25
+
26
+ Only text the owner typed is collected. Injected context, tool output and assistant text are
27
+ never collected.
28
+
29
+ | Source | Location | User text |
30
+ | --- | --- | --- |
31
+ | Claude Code | `~/.claude/projects/*/*.jsonl` | `type: "user"` records that are not meta or sidechain, string content or text parts |
32
+ | Codex | `~/.codex/sessions/**/*.jsonl` | `event_msg` `user_message.message`. Older sessions without it fall back to `response_item` user text |
33
+ | Copilot CLI | `~/.copilot/session-state/*/events.jsonl` | `user.message` `data.content` |
34
+ | VS Code Copilot Chat | `%APPDATA%/Code/User/workspaceStorage/*/chatSessions/*.json(l)` and `globalStorage/emptyWindowChatSessions` | `requests[].message.text` in snapshots (`kind: 0`) and request pushes (`kind: 2`, key `["requests"]`) |
35
+
36
+ The following are dropped:
37
+
38
+ - Text that starts with an injected wrapper tag, such as `<environment_context>`,
39
+ `<system-reminder>`, `<command-…>`, `<task-notification>` or `<ide_…>`.
40
+ - Tool results.
41
+ - Slash commands.
42
+ - Session-continuation summaries ("This session is being continued…").
43
+ - Empty text.
44
+
45
+ Codex sessions include prompts that another agent dispatched. They are kept and tagged with
46
+ their source, because Harness routes them in Codex too.
47
+
48
+ ## Filters, families and splits
49
+
50
+ - **Length**: at most 1024 UTF-8 bytes, which matches the checkpoint's `context_tokens`. A
51
+ longer prompt is still refused at inference and falls back to lexical routing. It is never
52
+ truncated.
53
+ - **Deduplication**: exact duplicates after whitespace normalization are dropped. The first
54
+ occurrence is kept.
55
+ - **Holdout leakage**: a prompt is dropped if its character-trigram Jaccard similarity to any
56
+ holdout prompt is at least 0.5. The same applies if either prompt contains the other after
57
+ normalization and the shorter one is more than 12 characters long. This matters because
58
+ the holdout includes rewrites of local prompt shapes.
59
+ - **Family**: the source session. Prompts from one conversation never span splits.
60
+ - **Split**: 15% of families go to `validation`, chosen by a stable SHA-256 of the family ID.
61
+ The rest go to `train`.
62
+
63
+ ## Privacy
64
+
65
+ - Collected prompts and labels stay on the local machine under
66
+ `~/.agents/harness-everything/system-one/training/` and are **never committed**. The
67
+ repository holds only the scripts, aggregate statistics and the SHA-256 of each dataset
68
+ file.
69
+ - Email addresses and user home paths are replaced with placeholders before storage. Names
70
+ and product terms are not reliably detectable and remain.
71
+ - The released weights come from a 4-way byte-level classifier with about 0.7M parameters. It
72
+ has no text-generation head, but a trained model can still encode fragments of its data.
73
+ The owner accepted this for their own prompts.
74
+ - Labeling sends the prompts to the Claude API. The owner authorized this.
75
+
76
+ ## Labeling
77
+
78
+ - **Labeler**: `claude -p` with Sonnet.
79
+ - Flags: `--setting-sources ""` (no hooks or plugins), `--no-session-persistence` (labeling
80
+ sessions never become collectable history), `--tools ""` and a JSON schema.
81
+ - The instructions contain the gold table and rules from
82
+ [system-one-corpus.md](system-one-corpus.md).
83
+ - Prompts go in batches of 100. Every returned index must be labeled exactly once with
84
+ `tier1`, `tier2`, `tier3` or `null`. A malformed batch is retried once and then
85
+ recorded as failed. It is never partially accepted.
86
+ - **Labeler check**: the labeler labels the 215 holdout prompts once, before any training
87
+ data is labeled. The report gives agreement with the owner's gold and the per-class recall.
88
+ - Labeling proceeds only when agreement is at least 80%.
89
+ - The instructions are never tuned on the holdout. If the check fails, the owner reviews
90
+ the disagreements and decides how to proceed.
91
+ - **Owner spot-check**: a random 5% sample of the labeled training data is reviewed on the
92
+ review page, and the disagreement rate is reported. The owner's decisions replace the LLM
93
+ labels for those cases.
94
+
95
+ ## Training and calibration
96
+
97
+ - **Model**: a new `cua_s1` `tinyx` scorer built with `make_system`.
98
+ - Config: `width` 128, `rank` 128, `layers` 2, `heads` 4, `context_tokens` 1024 and
99
+ `option_tokens` 96.
100
+ - Weights are initialized fresh, not from the forms checkpoint, whose domain and
101
+ positional range differ.
102
+ - **Target**: each example is the fixed tier catalog with the index of the gold option.
103
+ `null` maps to `unclassified`.
104
+ - **Optimization**:
105
+ - Cross-entropy, AdamW, a fixed seed and CPU.
106
+ - The epoch with the lowest validation negative log-likelihood is kept.
107
+ - The checkpoint metadata records the dataset hashes, the config and the validation metrics.
108
+ - **Calibration**: `minConfidence` and `minMargin` are chosen on validation to maximize
109
+ coverage, subject to an accepted precision of at least 98%. The router currently uses the
110
+ Phase 0 defaults (0.9 and 0.2). Carrying calibrated thresholds into the manifest is a
111
+ separate contract change.
112
+
113
+ ## Evaluation and release
114
+
115
+ - **Evaluation**: `scripts/evaluate-system-one.js` runs once on
116
+ `benchmarks/fixtures/system-one-holdout.json` with the new manifest. The rollout gates and
117
+ the lexical baseline (macro-F1 0.254) decide the result. The report goes under
118
+ `benchmarks/results/system-one/`.
119
+ - **Release**: the `.safetensors` and `.json` files are attached to a GitHub release. The
120
+ installer's pins gain the new model ID, revision, `domain: "harness-routing-v1"` and both
121
+ SHA-256 values. Until every rollout gate passes, the router default stays `off`.
@@ -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.22.1
7
+ version: 0.24.0
8
8
  ---
9
9
 
10
10
  # Harness Everything