harness-everything 0.22.1 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +6 -0
- package/benchmarks/fixtures/system-one-holdout-draft.json +2039 -0
- package/benchmarks/fixtures/system-one-holdout-reviews.json +1587 -0
- package/benchmarks/fixtures/system-one-holdout.json +7315 -0
- package/benchmarks/results/system-one/lexical-baseline-reviewed-holdout-2026-09-23/README.md +47 -0
- package/benchmarks/results/system-one/lexical-baseline-reviewed-holdout-2026-09-23/report.json +5222 -0
- package/ci/mechanism-system-one-corpus.test.js +154 -0
- package/docs/system-one-corpus.md +103 -0
- package/docs/system-one-routing.md +2 -1
- package/opencode-plugin/plugin.json +1 -1
- package/package.json +1 -1
- package/plugins/harness-everything/.codex-plugin/plugin.json +1 -1
- package/plugins/harness-everything/plugin.json +1 -1
- package/sbom.cdx.json +7 -7
- package/scripts/system-one-corpus.js +99 -0
|
@@ -0,0 +1,154 @@
|
|
|
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 { validateDraft, validateReviews, build, promptHash } = require('../scripts/system-one-corpus');
|
|
10
|
+
const { validateCorpus } = require('../harness-everything/scripts/system-one/evaluate');
|
|
11
|
+
const root = path.resolve(__dirname, '..');
|
|
12
|
+
const draftPath = path.join(root, 'benchmarks/fixtures/system-one-holdout-draft.json');
|
|
13
|
+
|
|
14
|
+
const draftCase = (id, language = 'en', proposedGold = 'tier1', prompt = `commit the change for case ${id}`) => ({
|
|
15
|
+
id, family: `family-${id}`, language, source: 'synthetic:authored', prompt, proposedGold, rationale: 'bounded git operation' });
|
|
16
|
+
const draft = () => ({ schemaVersion: 1, cases: [draftCase('a'), draftCase('b', 'zh-TW', null, '繼續'), draftCase('c', 'en', 'tier2', 'fix the failing parser test and rerun it')] });
|
|
17
|
+
const decision = (c, kind = 'accept', gold = c.proposedGold) => ({ id: c.id, promptHash: promptHash(c.prompt), decision: kind, gold, reviewer: 'human:repository-owner' });
|
|
18
|
+
const reviews = decisions => ({ schemaVersion: 1, decisions });
|
|
19
|
+
|
|
20
|
+
test('S1-K01 an unreviewed draft assembles into a valid corpus that cannot pass the review gate', () => {
|
|
21
|
+
const { corpus, summary } = build(draft(), null);
|
|
22
|
+
assert.equal(validateCorpus(corpus), true);
|
|
23
|
+
assert.ok(corpus.cases.every(c => c.reviewed === false && c.split === 'holdout'));
|
|
24
|
+
assert.deepEqual(corpus.cases.map(c => c.gold), ['tier1', null, 'tier2']);
|
|
25
|
+
assert.equal(corpus.cases[1].request.context, '繼續');
|
|
26
|
+
assert.equal(summary.unreviewed, 3);
|
|
27
|
+
assert.equal(summary.reviewedHoldoutGate, false);
|
|
28
|
+
assert.equal(promptHash('繼續'), createHash('sha256').update('繼續', 'utf8').digest('hex'));
|
|
29
|
+
assert.deepEqual(build(draft(), null), build(draft(), null));
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test('S1-K02 accept, relabel and reject apply exactly; the reviewer gold wins', () => {
|
|
33
|
+
const d = draft();
|
|
34
|
+
const { corpus, summary } = build(d, reviews([decision(d.cases[0]), decision(d.cases[1], 'relabel', 'tier1'), decision(d.cases[2], 'reject', null)]));
|
|
35
|
+
assert.deepEqual(corpus.cases.map(c => [c.id, c.gold, c.reviewed]), [['a', 'tier1', true], ['b', 'tier1', true]]);
|
|
36
|
+
assert.equal(summary.rejected, 1);
|
|
37
|
+
assert.equal(summary.reviewed, 2);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test('S1-K03 a decision for changed prompt text is stale and never counts as review', () => {
|
|
41
|
+
const d = draft();
|
|
42
|
+
const r = reviews([decision(d.cases[0], 'relabel', 'tier2')]);
|
|
43
|
+
d.cases[0].prompt = 'commit and push the change for case a';
|
|
44
|
+
const { corpus, summary } = build(d, r);
|
|
45
|
+
assert.equal(corpus.cases[0].reviewed, false);
|
|
46
|
+
assert.equal(corpus.cases[0].gold, 'tier1');
|
|
47
|
+
assert.equal(summary.stale, 1);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test('S1-K04 malformed reviews are rejected instead of silently applied', () => {
|
|
51
|
+
const d = draft();
|
|
52
|
+
const bad = [
|
|
53
|
+
r => { r.decisions.push({ ...r.decisions[0] }); },
|
|
54
|
+
r => { r.decisions[0].id = 'unknown'; },
|
|
55
|
+
r => { r.decisions[0].decision = 'approve'; },
|
|
56
|
+
r => { r.decisions[0].gold = 'tier3'; },
|
|
57
|
+
r => { r.decisions[0] = decision(d.cases[0], 'relabel', 'tier1'); },
|
|
58
|
+
r => { r.decisions[0] = decision(d.cases[0], 'reject', 'tier1'); },
|
|
59
|
+
r => { r.decisions[0].reviewer = 'claude'; },
|
|
60
|
+
r => { r.decisions[0].reviewer = 'human:someone@example.com'; },
|
|
61
|
+
r => { r.decisions[0].extra = true; },
|
|
62
|
+
r => { r.decisions[0].promptHash = 'abc'; },
|
|
63
|
+
r => { r.schemaVersion = 2; },
|
|
64
|
+
];
|
|
65
|
+
for (const mutate of bad) {
|
|
66
|
+
const r = reviews([decision(d.cases[0])]);
|
|
67
|
+
mutate(r);
|
|
68
|
+
assert.throws(() => build(d, r));
|
|
69
|
+
}
|
|
70
|
+
assert.equal(validateReviews(reviews([decision(d.cases[0])])), true);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test('S1-K05 draft validation: exact fields, unique ids and prompts, known sources, no private data', () => {
|
|
74
|
+
assert.equal(validateDraft(draft()), true);
|
|
75
|
+
const bad = [
|
|
76
|
+
d => { d.cases[1].id = 'a'; },
|
|
77
|
+
d => { d.cases[1].prompt = d.cases[0].prompt; },
|
|
78
|
+
d => { d.cases[0].source = 'real:history'; },
|
|
79
|
+
d => { d.cases[0].language = 'ja'; },
|
|
80
|
+
d => { d.cases[0].proposedGold = 'unclassified'; },
|
|
81
|
+
d => { d.cases[0].rationale = ''; },
|
|
82
|
+
d => { d.cases[0].extra = 1; },
|
|
83
|
+
d => { d.cases = []; },
|
|
84
|
+
d => { d.cases[0].prompt = 'mail the report to dev.lead@example.com'; },
|
|
85
|
+
d => { d.cases[0].prompt = 'open C:\\Users\\alice\\repo\\notes.md and fix it'; },
|
|
86
|
+
d => { d.cases[0].prompt = 'read /home/alice/project/config.yaml'; },
|
|
87
|
+
d => { d.cases[0].prompt = 'read /Users/alice/project/config.yaml'; },
|
|
88
|
+
];
|
|
89
|
+
for (const mutate of bad) { const d = draft(); mutate(d); assert.throws(() => validateDraft(d)); }
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test('S1-K06 the gate passes only with >=200 reviewed cases and >=50 per language', () => {
|
|
93
|
+
const make = (en, zh) => ({ schemaVersion: 1, cases: [
|
|
94
|
+
...Array.from({ length: en }, (_, i) => draftCase(`en-${i}`, 'en', 'tier1', `rename variable number ${i} in the parser`)),
|
|
95
|
+
...Array.from({ length: zh }, (_, i) => draftCase(`zh-${i}`, 'zh-TW', 'tier1', `把第 ${i} 個變數改名`)),
|
|
96
|
+
] });
|
|
97
|
+
const all = d => reviews(d.cases.map(c => decision(c)));
|
|
98
|
+
const pass = make(150, 50);
|
|
99
|
+
assert.equal(build(pass, all(pass)).summary.reviewedHoldoutGate, true);
|
|
100
|
+
const fewZh = make(160, 49);
|
|
101
|
+
assert.equal(build(fewZh, all(fewZh)).summary.reviewedHoldoutGate, false);
|
|
102
|
+
const partial = make(150, 50);
|
|
103
|
+
assert.equal(build(partial, reviews(all(partial).decisions.slice(1))).summary.reviewedHoldoutGate, false);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
test('S1-K07 CLI builds a corpus file and fails closed on invalid input', () => {
|
|
107
|
+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'harness-s1-corpus-'));
|
|
108
|
+
try {
|
|
109
|
+
const cli = path.join(root, 'scripts/system-one-corpus.js');
|
|
110
|
+
const input = path.join(dir, 'draft.json'); const review = path.join(dir, 'reviews.json'); const out = path.join(dir, 'corpus.json');
|
|
111
|
+
const d = draft();
|
|
112
|
+
fs.writeFileSync(input, JSON.stringify(d));
|
|
113
|
+
fs.writeFileSync(review, JSON.stringify(reviews([decision(d.cases[0])])));
|
|
114
|
+
const ok = spawnSync(process.execPath, [cli, 'build', input, review, out], { encoding: 'utf8' });
|
|
115
|
+
assert.equal(ok.status, 0, ok.stderr);
|
|
116
|
+
assert.equal(JSON.parse(ok.stdout).reviewed, 1);
|
|
117
|
+
assert.equal(validateCorpus(JSON.parse(fs.readFileSync(out, 'utf8'))), true);
|
|
118
|
+
const none = spawnSync(process.execPath, [cli, 'build', input, '-', out], { encoding: 'utf8' });
|
|
119
|
+
assert.equal(none.status, 0, none.stderr);
|
|
120
|
+
assert.equal(JSON.parse(none.stdout).reviewed, 0);
|
|
121
|
+
fs.writeFileSync(review, '{"schemaVersion":1,"decisions":[{"id":"zzz"}]}');
|
|
122
|
+
assert.equal(spawnSync(process.execPath, [cli, 'build', input, review, out], { encoding: 'utf8' }).status, 1);
|
|
123
|
+
assert.equal(spawnSync(process.execPath, [cli, 'bogus'], { encoding: 'utf8' }).status, 1);
|
|
124
|
+
} finally { fs.rmSync(dir, { recursive: true, force: true }); }
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
test('S1-K08 the committed holdout draft meets size, language, class and length requirements', () => {
|
|
128
|
+
const d = JSON.parse(fs.readFileSync(draftPath, 'utf8'));
|
|
129
|
+
assert.equal(validateDraft(d), true);
|
|
130
|
+
const { corpus } = build(d, null);
|
|
131
|
+
assert.equal(validateCorpus(corpus), true);
|
|
132
|
+
assert.ok(d.cases.length >= 220, 'headroom above 200 for rejected cases');
|
|
133
|
+
for (const lang of ['en', 'zh-TW']) assert.ok(d.cases.filter(c => c.language === lang).length >= 60, lang);
|
|
134
|
+
for (const gold of ['tier1', 'tier2', 'tier3', null]) assert.ok(d.cases.filter(c => c.proposedGold === gold).length >= 40, String(gold));
|
|
135
|
+
const bytes = d.cases.map(c => Buffer.byteLength(c.prompt, 'utf8'));
|
|
136
|
+
assert.ok(bytes.filter(b => b > 224).length / bytes.length >= 0.15, 'long prompts are represented');
|
|
137
|
+
assert.ok(bytes.filter(b => b <= 40).length / bytes.length >= 0.1, 'short prompts are represented');
|
|
138
|
+
assert.ok(d.cases.some(c => c.source === 'derived:local-history') && d.cases.some(c => c.source === 'synthetic:authored'));
|
|
139
|
+
assert.ok(new Set(d.cases.map(c => c.family)).size >= 40, 'enough distinct families');
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
test('S1-K09 the committed reviewed holdout is reproducible from owner decisions and meets the gate', () => {
|
|
143
|
+
const read = name => JSON.parse(fs.readFileSync(path.join(root, 'benchmarks/fixtures', name), 'utf8'));
|
|
144
|
+
const d = read('system-one-holdout-draft.json');
|
|
145
|
+
const r = read('system-one-holdout-reviews.json');
|
|
146
|
+
assert.equal(validateReviews(r), true);
|
|
147
|
+
assert.deepEqual(r.decisions.map(x => x.id).sort(), d.cases.map(c => c.id).sort(), 'every draft case has exactly one owner decision');
|
|
148
|
+
const { corpus, summary } = build(d, r);
|
|
149
|
+
assert.equal(summary.stale, 0);
|
|
150
|
+
assert.equal(summary.unreviewed, 0);
|
|
151
|
+
assert.equal(summary.reviewedHoldoutGate, true);
|
|
152
|
+
assert.deepEqual(read('system-one-holdout.json'), corpus, 'committed corpus equals the rebuild');
|
|
153
|
+
for (const gold of ['tier1', 'tier2', 'tier3', null]) assert.ok(corpus.cases.filter(c => c.gold === gold).length >= 15, String(gold));
|
|
154
|
+
});
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# System One holdout corpus: labeling and review
|
|
2
|
+
|
|
3
|
+
This document defines how the reviewed tier holdout for
|
|
4
|
+
[System One](system-one-routing.md) is written, labeled, reviewed and
|
|
5
|
+
assembled (issue [#233](https://github.com/dyphn1/Harness-everything/issues/233),
|
|
6
|
+
Phase 3). The `reviewedHoldout` gate requires at least 200 holdout cases, at
|
|
7
|
+
least 50 per language, and `reviewed: true` on every case.
|
|
8
|
+
|
|
9
|
+
## Gold labels
|
|
10
|
+
|
|
11
|
+
A gold label answers one question: **which tier should Harness route this prompt
|
|
12
|
+
to, judged from the prompt alone?** The labels follow the tier model in
|
|
13
|
+
[routing.md](routing.md#three-tier-routing-model) and the fixed tier catalog.
|
|
14
|
+
|
|
15
|
+
| Gold | Use when the prompt asks for | Examples of shape |
|
|
16
|
+
| --- | --- | --- |
|
|
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
|
+
| `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" |
|
|
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
|
+
|
|
22
|
+
Rules:
|
|
23
|
+
|
|
24
|
+
1. Label the work the prompt would start. A reply that settles decisions for
|
|
25
|
+
work in progress ("1. agree 2. use hash") is labeled by that work, not `null`.
|
|
26
|
+
Use `null` only when no work can be identified at all.
|
|
27
|
+
2. Label the work requested, not the words used. Searching every repository and
|
|
28
|
+
reporting is `tier1`; changing every repository is `tier3`.
|
|
29
|
+
3. Pick the smallest tier that covers the whole request.
|
|
30
|
+
4. Explicit workflow words ("use fable", "no subagents") do not change the gold.
|
|
31
|
+
Precedence is a router policy, not a label.
|
|
32
|
+
5. Never derive gold from the lexical router or any model output. A reviewer may
|
|
33
|
+
read the proposed gold, but the recorded gold is the reviewer's decision.
|
|
34
|
+
|
|
35
|
+
These definitions are the repository owner's, recorded after the first review
|
|
36
|
+
of the draft: the owner's labels moved many drafted cases one tier up, labeled
|
|
37
|
+
context-dependent replies by their work, and gave non-engineering chores
|
|
38
|
+
`tier1`. The draft's `proposedGold` values predate this and are only
|
|
39
|
+
suggestions. Acknowledgements, reactions, host commands (`/compact`) and meeting
|
|
40
|
+
notes were rejected from the holdout because they never reach routing as tasks.
|
|
41
|
+
|
|
42
|
+
## Cases
|
|
43
|
+
|
|
44
|
+
Each draft case has `id`, `family`, `language` (`en` or `zh-TW`), `source`,
|
|
45
|
+
`prompt`, `proposedGold` and a one-line `rationale`.
|
|
46
|
+
|
|
47
|
+
- **Family.** A family groups prompts that share one task scenario, such as
|
|
48
|
+
"commit and push" or "fix a CLI error from a pasted log". Paraphrases,
|
|
49
|
+
translations and variants of one scenario stay in one family, and a family
|
|
50
|
+
never spans splits. All families in this corpus are `holdout`. Later train or
|
|
51
|
+
validation data must use new families.
|
|
52
|
+
- **Source.** `synthetic:authored` marks a prompt written for the corpus.
|
|
53
|
+
`derived:local-history` marks a prompt rewritten from the shape of a real
|
|
54
|
+
local prompt: same length class, task type and phrasing style, with every
|
|
55
|
+
name, path, product, customer, issue number and pasted log replaced. No real
|
|
56
|
+
prompt text, person, organization or local path is committed.
|
|
57
|
+
- **Length.** The corpus follows the observed length profile of real local
|
|
58
|
+
prompts (median about 90 UTF-8 bytes, about one in five over 224 bytes, a
|
|
59
|
+
long tail with pasted logs), so that length limits are evaluated on realistic
|
|
60
|
+
input, not only short prompts.
|
|
61
|
+
|
|
62
|
+
## Review
|
|
63
|
+
|
|
64
|
+
A human reviewer decides every case on the review page. The possible decisions are:
|
|
65
|
+
|
|
66
|
+
| Decision | Effect |
|
|
67
|
+
| --- | --- |
|
|
68
|
+
| `accept` | Gold is the proposed gold. |
|
|
69
|
+
| `relabel` | Gold is the reviewer's chosen label. |
|
|
70
|
+
| `reject` | The case is dropped: ambiguous even for a human, unrealistic, or it leaks private data. |
|
|
71
|
+
|
|
72
|
+
Each decision records the case ID, the SHA-256 of the exact prompt text it
|
|
73
|
+
reviewed (`promptHash`), the decision, the gold, and the reviewer role. The
|
|
74
|
+
assembler `scripts/system-one-corpus.js` builds the evaluation corpus from the
|
|
75
|
+
draft and the decisions:
|
|
76
|
+
|
|
77
|
+
- A case with a valid decision becomes `reviewed: true` with the reviewer's gold.
|
|
78
|
+
- A case without a decision, or whose prompt changed after review (hash
|
|
79
|
+
mismatch), stays `reviewed: false` with the proposed gold, so the gate cannot
|
|
80
|
+
pass on stale or missing review.
|
|
81
|
+
- A rejected case is omitted.
|
|
82
|
+
- The output passes `validateCorpus`, and the assembler reports per-language and
|
|
83
|
+
per-gold counts plus whether the `reviewedHoldout` gate would pass.
|
|
84
|
+
|
|
85
|
+
The agent that drafts cases never records decisions. `reviewed: true` means a
|
|
86
|
+
human reviewed that exact text. Review records store a role
|
|
87
|
+
(`human:repository-owner`), not a name or account. When a decision contradicts
|
|
88
|
+
the owner's decisions on sibling cases, the agent may ask the owner to confirm
|
|
89
|
+
it. The owner's answer is recorded as the decision, and the agent never changes
|
|
90
|
+
a decision on its own.
|
|
91
|
+
|
|
92
|
+
## Committed files
|
|
93
|
+
|
|
94
|
+
| File | Content |
|
|
95
|
+
| --- | --- |
|
|
96
|
+
| `benchmarks/fixtures/system-one-holdout-draft.json` | Draft cases with proposed gold |
|
|
97
|
+
| `benchmarks/fixtures/system-one-holdout-reviews.json` | Owner decisions (ID, prompt hash, decision, gold, role) |
|
|
98
|
+
| `benchmarks/fixtures/system-one-holdout.json` | Evaluation corpus, rebuilt with `node scripts/system-one-corpus.js build <draft> <reviews> <corpus>` |
|
|
99
|
+
|
|
100
|
+
The reviewed holdout has 215 cases (11 rejected): en 93 and zh-TW 122; gold
|
|
101
|
+
`tier1` 47, `tier2` 97, `tier3` 51 and `null` 20. It meets the `reviewedHoldout`
|
|
102
|
+
gate. It says nothing about model quality until a `harness-routing-v1`
|
|
103
|
+
checkpoint is evaluated on it.
|
|
@@ -227,7 +227,8 @@ The corpus is `{schemaVersion: 1, cases: [...]}`. Each case has exactly `id`,
|
|
|
227
227
|
The complete fixed tier catalog must match. IDs and request hashes are unique;
|
|
228
228
|
no family may span splits. Evaluation uses only holdout, never training labels.
|
|
229
229
|
The committed seed corpus is a mechanism fixture, not an independently reviewed
|
|
230
|
-
holdout.
|
|
230
|
+
holdout. The reviewed holdout is written, labeled and assembled as described in
|
|
231
|
+
[system-one-corpus.md](system-one-corpus.md).
|
|
231
232
|
|
|
232
233
|
The CLI runs the real lexical baseline and the configured provider twice per
|
|
233
234
|
holdout case. Records contain IDs, baseline prediction, decision, model identity,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
|
|
3
3
|
"name": "harness-everything",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.23.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",
|
package/sbom.cdx.json
CHANGED
|
@@ -2,23 +2,23 @@
|
|
|
2
2
|
"$schema": "https://cyclonedx.org/schema/bom-1.7.schema.json",
|
|
3
3
|
"bomFormat": "CycloneDX",
|
|
4
4
|
"specVersion": "1.7",
|
|
5
|
-
"serialNumber": "urn:uuid:
|
|
5
|
+
"serialNumber": "urn:uuid:a1c20a4d-4ba9-561e-92d1-aae9c14cdc08",
|
|
6
6
|
"version": 1,
|
|
7
7
|
"metadata": {
|
|
8
|
-
"timestamp": "2026-09-23T11:
|
|
8
|
+
"timestamp": "2026-09-23T11:44:30.450Z",
|
|
9
9
|
"tools": [
|
|
10
10
|
{
|
|
11
11
|
"vendor": "Harness Everything",
|
|
12
12
|
"name": "generate-sbom.js",
|
|
13
|
-
"version": "0.
|
|
13
|
+
"version": "0.23.0"
|
|
14
14
|
}
|
|
15
15
|
],
|
|
16
16
|
"component": {
|
|
17
17
|
"type": "application",
|
|
18
|
-
"bom-ref": "pkg:npm/harness-everything@0.
|
|
18
|
+
"bom-ref": "pkg:npm/harness-everything@0.23.0",
|
|
19
19
|
"name": "harness-everything",
|
|
20
|
-
"version": "0.
|
|
21
|
-
"purl": "pkg:npm/harness-everything@0.
|
|
20
|
+
"version": "0.23.0",
|
|
21
|
+
"purl": "pkg:npm/harness-everything@0.23.0"
|
|
22
22
|
}
|
|
23
23
|
},
|
|
24
24
|
"components": [
|
|
@@ -1999,7 +1999,7 @@
|
|
|
1999
1999
|
]
|
|
2000
2000
|
},
|
|
2001
2001
|
{
|
|
2002
|
-
"ref": "pkg:npm/harness-everything@0.
|
|
2002
|
+
"ref": "pkg:npm/harness-everything@0.23.0",
|
|
2003
2003
|
"dependsOn": [
|
|
2004
2004
|
"pkg:npm/%40commitlint/cli@19.8.1",
|
|
2005
2005
|
"pkg:npm/%40commitlint/config-conventional@19.8.1",
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
// Assembles the System One tier holdout from a draft plus human review decisions.
|
|
4
|
+
// See docs/system-one-corpus.md. A decision counts only for the exact prompt text it reviewed.
|
|
5
|
+
const fs = require('node:fs');
|
|
6
|
+
const { createHash } = require('node:crypto');
|
|
7
|
+
const { createRequest } = require('../harness-everything/scripts/system-one/contract');
|
|
8
|
+
const { TIER_OPTIONS } = require('../harness-everything/scripts/system-one/router');
|
|
9
|
+
const { validateCorpus } = require('../harness-everything/scripts/system-one/evaluate');
|
|
10
|
+
|
|
11
|
+
const SOURCES = ['synthetic:authored', 'derived:local-history'];
|
|
12
|
+
const LANGUAGES = ['en', 'zh-TW'];
|
|
13
|
+
const GOLD = ['tier1', 'tier2', 'tier3', null];
|
|
14
|
+
const REVIEWER = 'human:repository-owner';
|
|
15
|
+
// Drafts are committed publicly: no email addresses or user home paths.
|
|
16
|
+
const PRIVATE = [/[\w.+-]+@[\w-]+\.[\w.-]+/, /[A-Za-z]:\\Users\\/i, /\/home\/[^/\s]+/, /\/Users\/[^/\s]+/];
|
|
17
|
+
const exact = (v, keys) => v && typeof v === 'object' && !Array.isArray(v)
|
|
18
|
+
&& Object.keys(v).length === keys.length && keys.every(k => Object.hasOwn(v, k));
|
|
19
|
+
const nonempty = v => typeof v === 'string' && v.trim().length > 0;
|
|
20
|
+
const fail = code => { throw new TypeError(code); };
|
|
21
|
+
const promptHash = text => createHash('sha256').update(text, 'utf8').digest('hex');
|
|
22
|
+
|
|
23
|
+
function validateDraft(draft) {
|
|
24
|
+
if (!exact(draft, ['schemaVersion', 'cases']) || draft.schemaVersion !== 1 || !Array.isArray(draft.cases) || !draft.cases.length) fail('invalid-draft');
|
|
25
|
+
const ids = new Set(); const prompts = new Set();
|
|
26
|
+
for (const c of draft.cases) {
|
|
27
|
+
if (!exact(c, ['id', 'family', 'language', 'source', 'prompt', 'proposedGold', 'rationale'])
|
|
28
|
+
|| ![c.id, c.family, c.prompt, c.rationale].every(nonempty) || !/^[a-z0-9._-]{1,80}$/.test(c.id)
|
|
29
|
+
|| !LANGUAGES.includes(c.language) || !SOURCES.includes(c.source) || !GOLD.includes(c.proposedGold)
|
|
30
|
+
|| ids.has(c.id) || prompts.has(c.prompt) || PRIVATE.some(re => re.test(c.prompt))) fail('invalid-draft');
|
|
31
|
+
ids.add(c.id); prompts.add(c.prompt);
|
|
32
|
+
}
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function validateReviews(reviews) {
|
|
37
|
+
if (!exact(reviews, ['schemaVersion', 'decisions']) || reviews.schemaVersion !== 1 || !Array.isArray(reviews.decisions)) fail('invalid-reviews');
|
|
38
|
+
const ids = new Set();
|
|
39
|
+
for (const d of reviews.decisions) {
|
|
40
|
+
if (!exact(d, ['id', 'promptHash', 'decision', 'gold', 'reviewer']) || !nonempty(d.id) || ids.has(d.id)
|
|
41
|
+
|| typeof d.promptHash !== 'string' || !/^[0-9a-f]{64}$/.test(d.promptHash)
|
|
42
|
+
|| !['accept', 'relabel', 'reject'].includes(d.decision) || !GOLD.includes(d.gold) || d.reviewer !== REVIEWER
|
|
43
|
+
|| (d.decision === 'reject' && d.gold !== null)) fail('invalid-reviews');
|
|
44
|
+
ids.add(d.id);
|
|
45
|
+
}
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function build(draft, reviews) {
|
|
50
|
+
validateDraft(draft);
|
|
51
|
+
const byId = new Map();
|
|
52
|
+
if (reviews !== null) {
|
|
53
|
+
validateReviews(reviews);
|
|
54
|
+
for (const d of reviews.decisions) {
|
|
55
|
+
const c = draft.cases.find(item => item.id === d.id);
|
|
56
|
+
if (!c) fail('unknown-review-case');
|
|
57
|
+
// Accept keeps the proposed gold; relabel must change it. Checked against the current proposal.
|
|
58
|
+
if ((d.decision === 'accept' && d.gold !== c.proposedGold) || (d.decision === 'relabel' && d.gold === c.proposedGold)) fail('invalid-reviews');
|
|
59
|
+
byId.set(d.id, d);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const summary = { cases: 0, reviewed: 0, rejected: 0, stale: 0, unreviewed: 0,
|
|
63
|
+
byLanguage: { en: 0, 'zh-TW': 0 }, byGold: { tier1: 0, tier2: 0, tier3: 0, unclassified: 0 }, reviewedHoldoutGate: false };
|
|
64
|
+
const cases = [];
|
|
65
|
+
for (const c of draft.cases) {
|
|
66
|
+
const d = byId.get(c.id);
|
|
67
|
+
const current = d && d.promptHash === promptHash(c.prompt);
|
|
68
|
+
if (d && !current) summary.stale += 1;
|
|
69
|
+
if (current && d.decision === 'reject') { summary.rejected += 1; continue; }
|
|
70
|
+
const reviewed = Boolean(current);
|
|
71
|
+
if (reviewed) summary.reviewed += 1; else if (!d) summary.unreviewed += 1;
|
|
72
|
+
const gold = reviewed ? d.gold : c.proposedGold;
|
|
73
|
+
cases.push({ id: c.id, family: c.family, split: 'holdout', language: c.language, source: c.source, reviewed,
|
|
74
|
+
request: createRequest('tier', c.prompt, TIER_OPTIONS), gold });
|
|
75
|
+
summary.byLanguage[c.language] += 1;
|
|
76
|
+
summary.byGold[gold === null ? 'unclassified' : gold] += 1;
|
|
77
|
+
}
|
|
78
|
+
summary.cases = cases.length;
|
|
79
|
+
const corpus = { schemaVersion: 1, cases };
|
|
80
|
+
validateCorpus(corpus);
|
|
81
|
+
summary.reviewedHoldoutGate = cases.length >= 200 && cases.every(c => c.reviewed)
|
|
82
|
+
&& LANGUAGES.every(lang => summary.byLanguage[lang] >= 50);
|
|
83
|
+
return { corpus, summary };
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (require.main === module) {
|
|
87
|
+
try {
|
|
88
|
+
const [op, draftPath, reviewsPath, outPath, extra] = process.argv.slice(2);
|
|
89
|
+
if (op !== 'build' || !draftPath || !reviewsPath || !outPath || extra) throw new Error('usage');
|
|
90
|
+
const read = file => JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
91
|
+
const { corpus, summary } = build(read(draftPath), reviewsPath === '-' ? null : read(reviewsPath));
|
|
92
|
+
fs.writeFileSync(outPath, `${JSON.stringify(corpus, null, 2)}\n`);
|
|
93
|
+
console.log(JSON.stringify(summary));
|
|
94
|
+
} catch (_) {
|
|
95
|
+
console.error('Usage: system-one-corpus.js build <draft.json> <reviews.json|-> <corpus.json> (invalid draft, reviews, or path)');
|
|
96
|
+
process.exitCode = 1;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
module.exports = { validateDraft, validateReviews, build, promptHash, REVIEWER };
|