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
@@ -85,3 +85,20 @@ test('S1-E07 source provenance gate requires the pinned cua_s1 revision', () =>
85
85
  assert.equal(evaluate(make(), records(), recorded('pinned')).gates.sourceProvenance, true);
86
86
  assert.equal(evaluate(make(), records(), recorded('pinned')).rolloutReady, false);
87
87
  });
88
+ test('S1-E09 an ngram source passes provenance only with a verified artifact', () => {
89
+ const ngramSource = verified => ({ status: 'recorded', transport: 'ngram', artifactVerified: verified });
90
+ assert.equal(evaluate(make(), records(), ngramSource(true)).gates.sourceProvenance, true);
91
+ assert.equal(evaluate(make(), records(), ngramSource(false)).gates.sourceProvenance, false);
92
+ assert.equal(evaluate(make(), records(), { status: 'recorded', transport: 'ngram' }).gates.sourceProvenance, false);
93
+ assert.equal(evaluate(make(), records(), { status: 'unavailable', reason: 'provider-config', transport: 'ngram', artifactVerified: true }).gates.sourceProvenance, false);
94
+ });
95
+ test('S1-E08 the accepted-precision gate is the owner advisory 85%', () => {
96
+ // 7 accepted tier1 answers: 6 correct (85.7%) passes, 5 correct (71.4%) fails.
97
+ const cases = Array.from({ length: 7 }, (_, i) => ({ id: `p${i}`, family: `f${i}`, split: 'holdout', language: 'en', source: 'human:fixture', reviewed: false,
98
+ request: createRequest('tier', `bounded prompt ${i}`, TIER_OPTIONS), gold: 'tier1' }));
99
+ const corpus = { schemaVersion: 1, cases };
100
+ const recs = wrong => cases.map((c, i) => { const id = i < wrong ? 'tier2' : 'tier1';
101
+ return { id: c.id, baseline: 'tier2', runs: [0, 1].map(() => ({ decision: decision(id), scores: oneHot(id), latencyMs: 20, coldStart: true })) }; });
102
+ assert.equal(evaluate(corpus, recs(1)).gates.acceptedPrecision, true);
103
+ assert.equal(evaluate(corpus, recs(2)).gates.acceptedPrecision, false);
104
+ });
@@ -61,6 +61,33 @@ test('S1-L03 invalid replies are retried once, persistent failures are recorded,
61
61
  assert.equal(again.labeled.length, 0);
62
62
  });
63
63
 
64
+ test('S1-L06 the codex engine runs one stateless exec per batch and reads the schema-checked last message', () => {
65
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'harness-s1-codex-'));
66
+ try {
67
+ // Fake codex: records its argv, reads the prompt from stdin, writes the reply to the -o file.
68
+ const fake = path.join(dir, 'fake-codex.js'); const argvLog = path.join(dir, 'argv.json');
69
+ // Without an -o target the fake exits instead of writing (a[-1 + 1] would land in the working directory).
70
+ fs.writeFileSync(fake, `const fs=require('fs');const a=process.argv.slice(2);fs.writeFileSync(${JSON.stringify(argvLog)},JSON.stringify(a));
71
+ const o=a.indexOf('-o');if(o<0)process.exit(3);
72
+ let s='';process.stdin.on('data',d=>s+=d).on('end',()=>{const m=[...s.matchAll(/\\{"i":(\\d+),"text"/g)];
73
+ fs.writeFileSync(a[o+1],JSON.stringify({labels:m.map(x=>({i:Number(x[1]),gold:'tier1'}))}));});`);
74
+ const input = path.join(dir, 'prompts.jsonl');
75
+ fs.writeFileSync(input, items(3).map(r => JSON.stringify({ ...r, family: 'f', source: 'claude', split: 'train' })).join('\n') + '\n');
76
+ const out = path.join(dir, 'labels.jsonl');
77
+ const r = spawnSync(process.execPath, [path.join(root, 'scripts/system-one-label.js'), 'label', '--engine', 'codex', '--in', input, '--out', out],
78
+ { encoding: 'utf8', cwd: root, env: { ...process.env, HARNESS_S1_LABEL_COMMAND: JSON.stringify([process.execPath, fake]) } });
79
+ assert.equal(r.status, 0, r.stderr);
80
+ assert.deepEqual(JSON.parse(r.stdout), { labeled: 3, failed: 0, total: 3 });
81
+ const rows = fs.readFileSync(out, 'utf8').trim().split('\n').map(l => JSON.parse(l));
82
+ assert.ok(rows.every(x => x.gold === 'tier1' && x.labeler.model === 'gpt-5.6-luna' && x.labeler.engine === 'codex'));
83
+ const argv = JSON.parse(fs.readFileSync(argvLog, 'utf8'));
84
+ for (const flag of ['exec', '--ephemeral', '--ignore-user-config', '--output-schema', '-o']) assert.ok(argv.includes(flag), flag);
85
+ assert.equal(argv[argv.indexOf('--sandbox') + 1], 'read-only');
86
+ assert.equal(argv[argv.indexOf('--model') + 1], 'gpt-5.6-luna');
87
+ assert.equal(argv[argv.length - 1], '-', 'the prompt comes from stdin');
88
+ } finally { fs.rmSync(dir, { recursive: true, force: true }); }
89
+ });
90
+
64
91
  test('S1-L04 holdout agreement reports overall, per-class recall and confusion', () => {
65
92
  const gold = [['a', 'tier1'], ['b', 'tier1'], ['c', 'tier2'], ['d', null]];
66
93
  const pred = { a: 'tier1', b: 'tier2', c: 'tier2', d: null };
@@ -0,0 +1,161 @@
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 { createHash } = require('node:crypto');
8
+ const { spawnSync } = require('node:child_process');
9
+ const ngram = require('../harness-everything/scripts/system-one/ngram');
10
+ const provider = require('../harness-everything/scripts/system-one/provider');
11
+ const { createRequest, decide } = require('../harness-everything/scripts/system-one/contract');
12
+ const { TIER_OPTIONS } = require('../harness-everything/scripts/system-one/router');
13
+ const root = path.resolve(__dirname, '..');
14
+ const python = process.env.PYTHON || (process.platform === 'win32' ? 'python' : 'python3');
15
+ const sha = file => createHash('sha256').update(fs.readFileSync(file)).digest('hex');
16
+ const IDS = TIER_OPTIONS.map(o => o.id);
17
+
18
+ // A tiny model whose weights push any text containing the "commit" trigram toward tier1.
19
+ function artifact(dir, { dim = 1024, nmax = 3, catalog = IDS, sidecar = {}, bytes } = {}) {
20
+ const W = new Float32Array(dim * catalog.length);
21
+ const hot = ngram.fnv1a32('3:com') % dim;
22
+ W[hot * catalog.length + 0] = 40;
23
+ const bin = path.join(dir, 'tier.bin'); const json = path.join(dir, 'tier.json');
24
+ fs.writeFileSync(bin, bytes || Buffer.from(W.buffer));
25
+ fs.writeFileSync(json, JSON.stringify({ format: 'harness-ngram', formatVersion: 1, dim, nmax, hash: 'fnv1a32', catalog, bias: catalog.map(() => 0), metadata: { fixture: true }, ...sidecar }));
26
+ return { bin, json };
27
+ }
28
+ function manifest(dir, files, extra = {}) {
29
+ const m = { schemaVersion: 1, transport: 'ngram', checkpoint: files.bin, weightsSha256: sha(files.bin), configSha256: sha(files.json),
30
+ modelId: 'fixture/ngram', revision: 'v1', domain: 'harness-routing-v1', ...extra };
31
+ const p = path.join(dir, 'manifest.json'); fs.writeFileSync(p, JSON.stringify(m)); return { m, p };
32
+ }
33
+ const tmp = () => fs.mkdtempSync(path.join(os.tmpdir(), 'harness-s1-ngram-'));
34
+
35
+ test('S1-N01 fnv1a32 matches the published test vectors', () => {
36
+ assert.equal(ngram.fnv1a32(''), 0x811c9dc5);
37
+ assert.equal(ngram.fnv1a32('a'), 0xe40c292c);
38
+ assert.equal(ngram.fnv1a32('foobar'), 0xbf9cf968);
39
+ });
40
+
41
+ test('S1-N02 featurization follows the pinned rules', () => {
42
+ const f = ngram.featurize(' Commit ALL\tchanges ', 3, 1 << 16);
43
+ assert.deepEqual(f, ngram.featurize('commit all changes', 3, 1 << 16), 'lowercase and whitespace normalization');
44
+ const norm = Math.sqrt([...f.values()].reduce((s, v) => s + v * v, 0));
45
+ assert.ok(Math.abs(norm - 1) < 1e-12);
46
+ assert.ok(f.has(ngram.fnv1a32('len:4') % (1 << 16)), 'length bucket for 18 UTF-8 bytes');
47
+ const cjk = ngram.featurize('修正😀', 2, 1 << 16);
48
+ assert.ok(cjk.has(ngram.fnv1a32('2:正😀') % (1 << 16)), 'n-grams are over code points, not UTF-16 units');
49
+ assert.ok(!ngram.featurize('a b', 3, 1 << 16).has(ngram.fnv1a32('1: ') % (1 << 16)), 'space-only grams are skipped');
50
+ });
51
+
52
+ test('S1-N03 the Python trainer and the Node provider produce identical features', () => {
53
+ const texts = ['commit all changes', '幫我修正 parser 的錯誤並補測試', ' MIXED Case\ttext 😀 ', 'x', '重構 plugin 介面,跨兩個 repo'];
54
+ const hashes = ['', 'a', 'foobar', '3:修正測'];
55
+ const r = spawnSync(python, [path.join(__dirname, 'system-one-ngram-parity.py')], { input: JSON.stringify({ texts, hashes, nmax: 3, dim: 1 << 16 }), encoding: 'utf8', env: { ...process.env, PYTHONDONTWRITEBYTECODE: '1', PYTHONIOENCODING: 'utf-8' } });
56
+ assert.equal(r.status, 0, r.stderr);
57
+ const py = JSON.parse(r.stdout);
58
+ assert.deepEqual(py.hash, hashes.map(h => ngram.fnv1a32(h)));
59
+ texts.forEach((t, i) => {
60
+ const node = ngram.featurize(t, 3, 1 << 16);
61
+ assert.deepEqual(Object.keys(py.features[i]).map(Number).sort((a, b) => a - b), [...node.keys()].sort((a, b) => a - b), t);
62
+ for (const [k, v] of Object.entries(py.features[i])) assert.ok(Math.abs(v - node.get(Number(k))) < 1e-12, t);
63
+ });
64
+ });
65
+
66
+ test('S1-N04 the ngram transport scores in process with the Phase 0 response shape', async () => {
67
+ const dir = tmp();
68
+ try {
69
+ const { m, p } = manifest(dir, artifact(dir), { acceptance: { minConfidence: 0.5, minMargin: 0 } });
70
+ assert.equal(provider.validateManifest(m), true);
71
+ const request = createRequest('tier', 'please commit these changes', TIER_OPTIONS);
72
+ const result = provider.score(request, p);
73
+ assert.equal(result.status, 'scored');
74
+ assert.deepEqual(result.acceptance, { minConfidence: 0.5, minMargin: 0 });
75
+ assert.deepEqual(result.response.model, { id: 'fixture/ngram', revision: 'v1', domain: 'harness-routing-v1' });
76
+ assert.ok(Math.abs(result.response.scores.reduce((s, x) => s + x.probability, 0) - 1) < 1e-9);
77
+ const d = decide(request, result.response, result.acceptance);
78
+ assert.equal(d.status, 'accepted'); assert.equal(d.selectedId, 'tier1');
79
+ assert.deepEqual(await provider.scoreAsync(request, p), result);
80
+ const other = provider.score(createRequest('tier', 'unrelated words only', TIER_OPTIONS), p);
81
+ assert.ok(other.response.scores.every(s => Math.abs(s.probability - 0.25) < 1e-9), 'no active weights gives a uniform vector');
82
+ } finally { fs.rmSync(dir, { recursive: true, force: true }); }
83
+ });
84
+
85
+ test('S1-N05 any artifact mismatch is provider-config and never scores', () => {
86
+ const request = createRequest('tier', 'commit it', TIER_OPTIONS);
87
+ const cases = [
88
+ dir => { const f = artifact(dir); const { m, p } = manifest(dir, f); fs.appendFileSync(f.bin, Buffer.alloc(4)); return p; },
89
+ dir => { const f = artifact(dir, { bytes: Buffer.alloc(8) }); return manifest(dir, f).p; },
90
+ dir => manifest(dir, artifact(dir, { catalog: ['tier1', 'tier2', 'tier3', 'other'] })).p,
91
+ dir => manifest(dir, artifact(dir, { sidecar: { format: 'other' } })).p,
92
+ dir => manifest(dir, artifact(dir, { sidecar: { extra: 1 } })).p,
93
+ dir => manifest(dir, artifact(dir, { dim: 1000 })).p,
94
+ dir => manifest(dir, artifact(dir, { nmax: 9 })).p,
95
+ dir => manifest(dir, artifact(dir, { sidecar: { bias: [0, 0] } })).p,
96
+ ];
97
+ for (const make of cases) {
98
+ const dir = tmp();
99
+ try { assert.deepEqual(provider.score(request, make(dir)), { status: 'unavailable', reason: 'provider-config' }); }
100
+ finally { fs.rmSync(dir, { recursive: true, force: true }); }
101
+ }
102
+ });
103
+
104
+ test('S1-N06 manifest rules: ngram needs a .bin and no python; other transports still need python', () => {
105
+ const dir = tmp();
106
+ try {
107
+ const { m } = manifest(dir, artifact(dir));
108
+ assert.equal(provider.validateManifest(m), true);
109
+ assert.throws(() => provider.validateManifest({ ...m, checkpoint: m.checkpoint.replace(/\.bin$/, '.safetensors') }));
110
+ assert.throws(() => provider.validateManifest({ ...m, transport: 'resident' }), 'resident requires python and a .safetensors checkpoint');
111
+ assert.throws(() => provider.validateManifest({ ...m, transport: 'bogus' }));
112
+ } finally { fs.rmSync(dir, { recursive: true, force: true }); }
113
+ });
114
+
115
+ test('S1-N08 the evaluator records ngram samples warm and verifies the artifact as provenance', () => {
116
+ const dir = tmp();
117
+ try {
118
+ const { p } = manifest(dir, artifact(dir));
119
+ const output = path.join(dir, 'report.json');
120
+ const corpus = path.join(root, 'benchmarks/fixtures/system-one-routing.json');
121
+ const r = spawnSync(process.execPath, [path.join(root, 'scripts/evaluate-system-one.js'), corpus, p, output], { encoding: 'utf8', cwd: root });
122
+ assert.equal(r.status, 0, r.stderr);
123
+ const report = JSON.parse(fs.readFileSync(output, 'utf8'));
124
+ assert.ok(report.records.every(x => x.runs.every(run => run.coldStart === false)));
125
+ assert.equal(report.latency.coldSamples, 0);
126
+ assert.equal(report.gates.warmLatency, true);
127
+ assert.deepEqual(report.evidence.source, { status: 'recorded', transport: 'ngram', artifactVerified: true });
128
+ assert.equal(report.gates.sourceProvenance, true);
129
+ assert.equal(report.evidence.kind, 'offline-ngram');
130
+ fs.appendFileSync(path.join(dir, 'tier.bin'), Buffer.alloc(4));
131
+ const tampered = spawnSync(process.execPath, [path.join(root, 'scripts/evaluate-system-one.js'), corpus, p, output], { encoding: 'utf8', cwd: root });
132
+ assert.equal(tampered.status, 0, tampered.stderr);
133
+ const bad = JSON.parse(fs.readFileSync(output, 'utf8'));
134
+ assert.equal(bad.evidence.source.artifactVerified, false);
135
+ assert.equal(bad.gates.sourceProvenance, false);
136
+ assert.equal(bad.model.coverage, 0);
137
+ } finally { fs.rmSync(dir, { recursive: true, force: true }); }
138
+ });
139
+
140
+ test('S1-N07 a real ngram training run produces an artifact the provider scores (skipped without torch)', t => {
141
+ if (spawnSync(python, ['-c', 'import torch'], { encoding: 'utf8' }).status !== 0) { t.skip('torch not installed'); return; }
142
+ const dir = tmp();
143
+ try {
144
+ const data = path.join(dir, 'data'); fs.mkdirSync(data);
145
+ const texts = [['commit all changes', 'tier1'], ['push and open a pr', 'tier1'], ['add a new flag with tests', 'tier3'], ['migrate every service', 'tier3'], ['fix the failing parser test', 'tier2'], ['go', null]];
146
+ const prompts = []; const labels = [];
147
+ for (let k = 0; k < 10; k++) texts.forEach(([x, g], i) => { const id = `p${k}-${i}`; prompts.push({ id, family: `f${k}`, source: 'claude', split: k < 8 ? 'train' : 'validation', text: `${x} ${k}` }); labels.push({ id, gold: g }); });
148
+ fs.writeFileSync(path.join(data, 'prompts.jsonl'), prompts.map(x => JSON.stringify(x)).join('\n') + '\n');
149
+ fs.writeFileSync(path.join(data, 'labels.jsonl'), labels.map(x => JSON.stringify(x)).join('\n') + '\n');
150
+ const out = path.join(dir, 'model');
151
+ const r = spawnSync(python, [path.join(root, 'scripts/system-one-train-ngram.py'), '--data-dir', data, '--out', out, '--dim', '4096', '--epochs', '40'], { encoding: 'utf8' });
152
+ assert.equal(r.status, 0, r.stdout + r.stderr);
153
+ const files = { bin: path.join(out, 'harness-routing-v1.bin'), json: path.join(out, 'harness-routing-v1.json') };
154
+ assert.equal(fs.statSync(files.bin).size, 4096 * 4 * 4);
155
+ assert.equal(fs.readFileSync(path.join(out, 'val-scores.jsonl'), 'utf8').trim().split('\n').length, 12);
156
+ const { p } = manifest(dir, files);
157
+ const scored = provider.score(createRequest('tier', 'commit all changes now', TIER_OPTIONS), p);
158
+ assert.equal(scored.status, 'scored');
159
+ assert.equal(decide(createRequest('tier', 'commit all changes now', TIER_OPTIONS), scored.response, { minConfidence: 0.5, minMargin: 0 }).selectedId, 'tier1');
160
+ } finally { fs.rmSync(dir, { recursive: true, force: true }); }
161
+ });
@@ -41,6 +41,18 @@ test('S1-T03 calibration maximizes coverage subject to accepted precision on val
41
41
  assert.deepEqual(calibrate(rows, { minPrecision: 0.98 }), c, 'deterministic');
42
42
  });
43
43
 
44
+ test('S1-T06 the default calibration target is the owner advisory 85%', () => {
45
+ const rows = [
46
+ ...Array.from({ length: 86 }, () => row('tier1', [0.9, 0.05, 0.03, 0.02])),
47
+ ...Array.from({ length: 14 }, () => row('tier2', [0.9, 0.05, 0.03, 0.02])),
48
+ ];
49
+ const c = calibrate(rows);
50
+ assert.equal(c.minPrecision, 0.85);
51
+ assert.equal(c.feasible, true);
52
+ assert.equal(c.coverage, 1);
53
+ assert.equal(calibrate(rows, { minPrecision: 0.9 }).feasible, false);
54
+ });
55
+
44
56
  test('S1-T04 calibration CLI reads validation scores and writes thresholds', () => {
45
57
  const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'harness-s1-cal-'));
46
58
  try {
@@ -0,0 +1,19 @@
1
+ """Print the trainer's n-gram features for texts on stdin (JSON list) so the Node provider can be compared exactly."""
2
+ import importlib.util
3
+ import json
4
+ from pathlib import Path
5
+ import sys
6
+
7
+ sys.dont_write_bytecode = True
8
+ ROOT = Path(__file__).resolve().parents[1]
9
+ spec = importlib.util.spec_from_file_location('ngram_trainer', ROOT / 'scripts' / 'system-one-train-ngram.py')
10
+ trainer = importlib.util.module_from_spec(spec)
11
+ spec.loader.exec_module(trainer)
12
+ assert 'torch' not in sys.modules, 'importing the ngram trainer must not import torch'
13
+
14
+ request = json.loads(sys.stdin.read())
15
+ out = []
16
+ for text in request['texts']:
17
+ feats = trainer.featurize(text, request['nmax'], request['dim'])
18
+ out.append({str(k): v for k, v in sorted(feats.items())})
19
+ print(json.dumps({'hash': [trainer.fnv1a32(s) for s in request['hashes']], 'features': out}))
@@ -46,6 +46,12 @@ assert flat == list(range(len(lengths))), 'every example exactly once'
46
46
  assert all(len(b) * max(lengths[i] for i in b) <= 4096 or len(b) == 1 for b in batches), 'budget respected'
47
47
  assert batches == trainer.make_batches(lengths, token_budget=4096), 'deterministic'
48
48
 
49
+ weights = trainer.class_weights([0, 0, 0, 1, 2, 2], 4)
50
+ assert len(weights) == 4
51
+ assert weights[3] == 0.0, 'an absent class gets no weight'
52
+ assert weights[1] > weights[2] > weights[0], weights
53
+ assert abs(sum(w * n for w, n in zip(weights, [3, 1, 2, 0])) - 6) < 1e-9, 'weights average to 1 over the examples'
54
+
49
55
  with tempfile.TemporaryDirectory() as tmp:
50
56
  p = Path(tmp) / 'rows.jsonl'
51
57
  p.write_text('\n'.join(json.dumps(r) for r in prompts) + '\n', encoding='utf-8')
@@ -16,7 +16,7 @@ to, judged from the prompt alone?** The labels follow the tier model in
16
16
  | --- | --- | --- |
17
17
  | `tier1` | Something answered or done without changing project behavior: Git/GitHub housekeeping (commit, push, open a PR, sync, tag, post given results as a comment), a status check, reading a log or searching and reporting, the smallest doc fix (a typo, a link, an ignore entry), or a reply the assistant can give directly, including non-engineering chores and discussion questions | "commit these changes", "is issue 88 still open?", "find every repo still using the old logging package", "close the other apps" |
18
18
  | `tier2` | A bounded change or investigation: any code, configuration or CI edit (a rename, a value, a revert), running tests or a build, filing an issue, explaining code that must be read first, most bug fixes, a focused review or benchmark, planning or synthesis that produces documents (phase plans, an ADR, an overview), and answers that settle open decisions for work in progress | "rename tmp to buffer", "run npm test", "the CLI fails with this error, fix it", "1. agree 2. keep the old name" |
19
- | `tier3` | New or changed behavior delivered with tests, and anything larger: a new flag or format, a behavior change across producers and tests, a large refactor, a dependency upgrade with breakage, a migration, a repository-wide change, a multi-phase implementation, or delegation to several agents | "add a --verbose flag with tests", "migrate to ESM", "dispatch agents to audit every repo" |
19
+ | `tier3` | Work that needs several agents (sub-agents included); a new module or subsystem, a refactor, or a change to a framework or interface definition; or code or design work that spans several repositories or several workflows | "add a plugin system to the CLI", "refactor the parser into modules", "change the plugin interface", "dispatch agents to audit every repo" |
20
20
  | `null` | No actionable content: a bare continuation, "do what you said", a vague reaction, a question about what the assistant meant, or pasted status with no request | "go", "yes", "照剛剛說的改", "something is off here" |
21
21
 
22
22
  Rules:
@@ -31,6 +31,30 @@ Rules:
31
31
  reformat or extend the assistant's previous answer without changing files is
32
32
  `tier1`. A requested change to code or configuration, however small, is at
33
33
  least `tier2`. Only the smallest doc fixes listed in the table stay `tier1`.
34
+ The line between `tier2` and `tier3` is the owner's: `tier3` when the work
35
+ needs several agents or sub-agents, adds a feature, refactors, changes a
36
+ framework or interface definition, or spans several repositories or
37
+ workflows. Fixing, adjusting, investigating or reviewing existing behavior
38
+ within one workflow is `tier2`.
39
+ The owner settled four more lines from the third spot-check:
40
+ - **Git is `tier1` at any width.** Committing sub-repositories and then the
41
+ main repository is still housekeeping. "Several repositories" applies to
42
+ code or design work only.
43
+ - **Scope, not the word "add".** Adding an option, a function or a parser
44
+ inside one existing tool or component is `tier2`. A new module or
45
+ subsystem, or an addition that spans several components, is `tier3`.
46
+ A bug fix, even with a regression test, is `tier2`.
47
+ - **Repository-wide or cross-component work is `tier3`.** Replacing or
48
+ unifying a pattern across the repository (every `console.log`, all error
49
+ handling, every path in a report), upgrading a dependency and fixing what
50
+ breaks, a data migration, a CI matrix across platforms, or restructuring a
51
+ documentation tree is `tier3`, even when each edit is small.
52
+ - **A short reply follows the work in progress.** A reply that asks to
53
+ change an output (code, a document, an example) is `tier2`. Only a pure
54
+ question or a bare acknowledgement stays `tier1`.
55
+ - **Explicit agents or architecture make `tier3`.** A request for several
56
+ agents, a team discussion or a verifier pass, or one that redefines an
57
+ architecture, is `tier3` even when it is phrased as discussion.
34
58
  4. Explicit workflow words ("use fable", "no subagents") do not change the gold.
35
59
  Precedence is a router policy, not a label.
36
60
  5. Never derive gold from the lexical router or any model output. A reviewer may
@@ -102,6 +126,10 @@ a decision on its own.
102
126
  | `benchmarks/fixtures/system-one-holdout.json` | Evaluation corpus, rebuilt with `node scripts/system-one-corpus.js build <draft> <reviews> <corpus>` |
103
127
 
104
128
  The reviewed holdout has 215 cases (11 rejected): en 93 and zh-TW 122; gold
105
- `tier1` 47, `tier2` 97, `tier3` 51 and `null` 20. It meets the `reviewedHoldout`
106
- gate. It says nothing about model quality until a `harness-routing-v1`
129
+ `tier1` 48, `tier2` 104, `tier3` 43 and `null` 20. It meets the `reviewedHoldout`
130
+ gate. After the third training spot-check the owner moved nine cases to the new
131
+ lines: `h-long-git-ops-1` to `tier1`, and the `h-add-cli-flag-*`,
132
+ `h-hash-algorithm-support-1/2`, `h-fix-cli-error-log-3/4` and
133
+ `h-fix-failing-test-3` cases to `tier2`. Results recorded before that change
134
+ used 47 `tier1`, 97 `tier2` and 51 `tier3`. It says nothing about model quality until a `harness-routing-v1`
107
135
  checkpoint is evaluated on it.
@@ -103,6 +103,52 @@ responses are checked by Phase 0. Transport fixtures prove IPC and failure
103
103
  handling only. Real checkpoint inference and measured CPU latency remain a
104
104
  separate gate, with explicit unavailable evidence if dependencies are absent.
105
105
 
106
+ ## N-gram provider (Phase 4)
107
+
108
+ `transport: "ngram"` scores in the Node process itself. It needs no Python, no
109
+ torch, no resident server and no subprocess. It exists because a byte-level
110
+ transformer trained from scratch learned little beyond class priors on the
111
+ owner's data. A linear model over character n-grams learned more from the same
112
+ labels at about 1 MB. See
113
+ [harness-routing-v1-cpu-2026-09-24](../benchmarks/results/system-one/harness-routing-v1-cpu-2026-09-24/README.md).
114
+
115
+ **Artifact.** The manifest `checkpoint` is an absolute path to `<name>.bin`, and
116
+ `weightsSha256` is that file's hash. A `<name>.json` sidecar beside it has the
117
+ hash `configSha256`. `python` is not required for this transport. The sidecar
118
+ holds exactly:
119
+
120
+ | Field | Value |
121
+ | --- | --- |
122
+ | `format` | `harness-ngram` |
123
+ | `formatVersion` | `1` |
124
+ | `dim` | Feature buckets, a power of two between 2^10 and 2^20 |
125
+ | `nmax` | Longest n-gram, 1–4 |
126
+ | `hash` | `fnv1a32` |
127
+ | `catalog` | The option IDs in catalog order |
128
+ | `bias` | One number per option |
129
+ | `metadata` | An object with training provenance |
130
+
131
+ `.bin` holds `dim × catalog.length` little-endian float32 weights in row-major
132
+ order (feature, then option), so its size must equal `dim × options × 4` bytes.
133
+ Both files are hash-checked before use. Any mismatch in hash, shape or field
134
+ returns `provider-config` and never scores.
135
+
136
+ **Features.** Featurization is identical in the trainer and the provider, and a
137
+ cross-language test proves it.
138
+
139
+ 1. Lowercase the text and join its whitespace-separated parts with one space.
140
+ 2. For each n from 1 to `nmax`, take every n-gram of Unicode code points that is
141
+ not only spaces. Add it to bucket `fnv1a32("<n>:<gram>" as UTF-8) mod dim`.
142
+ 3. Add one length feature, bucket `fnv1a32("len:<k>") mod dim`, where
143
+ `k = min(8, floor(log2(utf8Bytes + 1)))`.
144
+ 4. Weight each bucket as `log(1 + count)` and L2-normalize the vector.
145
+
146
+ **Scoring.** The probabilities are `softmax(x·W + bias)` in catalog order. The
147
+ request's option IDs must equal `catalog`, or the result is `provider-config`.
148
+ The response has the Phase 0 shape, and the manifest `acceptance` thresholds
149
+ apply as for any transport. The Phase 0 context limit (64 KiB) is the only
150
+ length limit.
151
+
106
152
  ## Resident provider (Phase 4 prerequisite)
107
153
 
108
154
  The one-shot bridge pays Python start, `import torch` and checkpoint load on every
@@ -262,6 +308,15 @@ The latter evidence is not supplied by this offline runner, so it always reports
262
308
  those gates pending. With the one-shot adapter, all latency is cold and the warm
263
309
  gate also remains pending. Exporting a report never changes router defaults.
264
310
 
311
+ For the `ngram` transport, samples are recorded with `coldStart: false`, because
312
+ scoring happens in process. The evaluator loads and verifies the artifact once
313
+ before any timed sample, so that load is not part of the warm latency. The
314
+ source check does not run the Python `cua_s1` probe, which this transport does
315
+ not use. It records `{status: "recorded", transport: "ngram", artifactVerified}`,
316
+ where `artifactVerified` is true only when both artifact files load and match
317
+ their SHA-256 values. For this transport, the `sourceProvenance` gate passes
318
+ when `artifactVerified` is true.
319
+
265
320
  ## Model suitability
266
321
 
267
322
  The [CUA-S1-FORMS model card](https://huggingface.co/cua-ai/cua-s1-forms)
@@ -286,11 +341,38 @@ unversioned download during a prompt hook.
286
341
  Phase 4 training data, labeling, calibration and release are defined in
287
342
  [system-one-training.md](system-one-training.md).
288
343
 
344
+ ## Staged classification
345
+
346
+ System One answers three narrow questions in sequence instead of one broad
347
+ question. Each stage is its own fixed catalog, scorer request and holdout, so a
348
+ small model only has to separate a few options at a time.
349
+
350
+ 1. **Tier**: `tier1`, `tier2`, `tier3` or `unclassified`, following
351
+ [system-one-corpus.md](system-one-corpus.md).
352
+ 2. **Intent**: the kind of work the prompt asks for, drawn from a small fixed
353
+ catalog (for example: ask or explain, discuss or decide, Git/GitHub
354
+ operation, fix a bug, build a feature, refactor, review or audit, test or
355
+ verify, write docs, plan or spec, investigate). The intent catalog is the
356
+ owner's and is recorded in the corpus document before any intent labels.
357
+ 3. **Skills**: which canonical skills fit the prompt, scored against skill
358
+ descriptions. Only skills above the stage's calibrated threshold are
359
+ suggested, and they are suggestions, never required reads.
360
+
361
+ Each stage has its own gates, and a stage ships only when it passes them. Tier
362
+ comes first because the reviewed holdout exists for it. Later stages reuse the
363
+ same collector, labeler, trainer and evaluator with a different catalog.
364
+ Suggestions are advisory: explicit workflow requests, action gates, memory
365
+ ownership, the Rule of 3 and deterministic policy always take precedence.
366
+
289
367
  ## Rollout gates
290
368
 
291
369
  Phase 4 requires a separately reviewed, family-disjoint holdout of at least 200
292
- cases, at least 50 each in English and Traditional Chinese. Accepted precision
293
- must be ≥98%, coverage ≥80%, and macro-F1 at least the lexical baseline.
370
+ cases, at least 50 each in English and Traditional Chinese. System One output is
371
+ advisory: it informs the agent and suggests skills. It never grants or removes
372
+ policy. The owner therefore set the target at accepted precision ≥85% (the
373
+ 80–90% band), coverage ≥80%, and macro-F1 at least the lexical baseline. A
374
+ probabilistic scorer small enough to ship inside a skills plugin (a few MB, not
375
+ hundreds) is not expected to reach 98%.
294
376
  Policy invariants must remain intact in every case; repeat decisions twice with
295
377
  100% agreement. Record checkpoint/source hashes, CPU, OS, runtime, thread count,
296
378
  cold latency and warm p95 (target ≤100ms). Synthetic fixtures and mock providers
@@ -104,7 +104,19 @@ prompts written by an agent, not by the owner. VS Code terminal notifications
104
104
 
105
105
  ## Training and calibration
106
106
 
107
- - **Model**: a new `cua_s1` `tinyx` scorer built with `make_system`.
107
+ - **Tier engine**: `scripts/system-one-train-ngram.py` trains the `ngram` transport, a
108
+ multinomial logistic regression over hashed character n-gram features. Featurization
109
+ follows [system-one-routing.md](system-one-routing.md#n-gram-provider-phase-4).
110
+ - The trainer uses torch for the optimizer only. The features are stdlib Python and match
111
+ the Node provider exactly.
112
+ - The configuration (`nmax`, class weighting, weight decay) is chosen on validation
113
+ macro-F1. The first exploration picked `nmax` 3, square-root inverse-frequency class
114
+ weights and a weight decay of 1e-4.
115
+ - The output is the `.bin` weights, the `.json` sidecar and validation scores for
116
+ calibration.
117
+ - The `tinyx` path below is kept for comparison. Its first checkpoint learned little beyond
118
+ class priors.
119
+ - **Model** (`tinyx`): a new `cua_s1` `tinyx` scorer built with `make_system`.
108
120
  - Config: `width` 128, `rank` 128, `layers` 2, `heads` 4, `context_tokens` 1024 and
109
121
  `option_tokens` 96.
110
122
  - Weights are initialized fresh, not from the forms checkpoint, whose domain and
@@ -116,7 +128,7 @@ prompts written by an agent, not by the owner. VS Code terminal notifications
116
128
  - The epoch with the lowest validation negative log-likelihood is kept.
117
129
  - The checkpoint metadata records the dataset hashes, the config and the validation metrics.
118
130
  - **Calibration**: `minConfidence` and `minMargin` are chosen on validation to maximize
119
- coverage, subject to an accepted precision of at least 98%. The router currently uses the
131
+ coverage, subject to an accepted precision of at least 85% (the owner's advisory target). The router currently uses the
120
132
  Phase 0 defaults (0.9 and 0.2). Carrying calibrated thresholds into the manifest is a
121
133
  separate contract change.
122
134
 
@@ -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
  }