harness-everything 0.5.3 → 0.6.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/behavioral-evals/PAIRED-BENCHMARK.md +186 -0
- package/behavioral-evals/README.md +46 -0
- package/behavioral-evals/opencode-hardlock-live.js +301 -0
- package/behavioral-evals/paired-benchmark.js +781 -0
- package/ci/mechanism-31-opencode-hardlock-evidence.test.js +138 -0
- package/ci/mechanism-32-paired-benchmark.test.js +254 -0
- package/opencode-plugin/plugin.json +1 -1
- package/package.json +4 -1
- package/plugins/harness-everything/.codex-plugin/plugin.json +1 -1
- package/plugins/harness-everything/plugin.json +1 -1
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const helper = require('./test-helper');
|
|
4
|
+
const {
|
|
5
|
+
BLOCKED_MARKER,
|
|
6
|
+
HARDLOCK_MESSAGE,
|
|
7
|
+
INSTALLED_PLUGIN_NAME,
|
|
8
|
+
POST_REFLECTION_MARKER,
|
|
9
|
+
PRELOCK_MARKER,
|
|
10
|
+
verifyEvidence,
|
|
11
|
+
} = require('../behavioral-evals/opencode-hardlock-live');
|
|
12
|
+
|
|
13
|
+
console.log('\n[31] opencode live hard-lock evidence contract...');
|
|
14
|
+
|
|
15
|
+
function writeJson(file, value) {
|
|
16
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
17
|
+
fs.writeFileSync(file, JSON.stringify(value, null, 2));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function makeEvidence() {
|
|
21
|
+
const dir = helper.tempDir('.mechanism-test-opencode-live-evidence');
|
|
22
|
+
fs.mkdirSync(path.join(dir, 'workspace'), { recursive: true });
|
|
23
|
+
fs.mkdirSync(path.join(dir, 'state'), { recursive: true });
|
|
24
|
+
const pluginHash = 'a'.repeat(64);
|
|
25
|
+
writeJson(path.join(dir, 'metadata.json'), {
|
|
26
|
+
schemaVersion: 1,
|
|
27
|
+
stateIsolated: true,
|
|
28
|
+
installedPluginName: INSTALLED_PLUGIN_NAME,
|
|
29
|
+
pluginSha256: pluginHash,
|
|
30
|
+
installedPluginSha256: pluginHash,
|
|
31
|
+
});
|
|
32
|
+
const toolEvent = (input) => JSON.stringify({
|
|
33
|
+
type: 'tool',
|
|
34
|
+
part: { tool: 'edit', state: { input } },
|
|
35
|
+
});
|
|
36
|
+
fs.writeFileSync(path.join(dir, 'transcript.jsonl'), [
|
|
37
|
+
toolEvent({ filePath: 'probe.txt', text: PRELOCK_MARKER }),
|
|
38
|
+
toolEvent({ filePath: 'probe.txt', text: POST_REFLECTION_MARKER }),
|
|
39
|
+
toolEvent({ filePath: 'probe.txt', text: BLOCKED_MARKER }),
|
|
40
|
+
JSON.stringify({ type: 'text', part: { text: `${HARDLOCK_MESSAGE} after a repeat failure post-reflection.` } }),
|
|
41
|
+
'',
|
|
42
|
+
].join('\n'));
|
|
43
|
+
fs.writeFileSync(path.join(dir, 'stderr.txt'), '', 'utf8');
|
|
44
|
+
fs.writeFileSync(path.join(dir, 'workspace', 'probe.txt'), `baseline\n${PRELOCK_MARKER}\n${POST_REFLECTION_MARKER}\n`, 'utf8');
|
|
45
|
+
writeJson(path.join(dir, 'state', 'circuit-breaker.json'), {
|
|
46
|
+
failures: {
|
|
47
|
+
'npm test: HARNESS_LIVE_PROBE_RED': { count: 4, firstSeen: 1, lastSeen: 5 },
|
|
48
|
+
},
|
|
49
|
+
hardLock: true,
|
|
50
|
+
lastReflection: 4,
|
|
51
|
+
lastReflectionSignature: 'npm test: HARNESS_LIVE_PROBE_RED',
|
|
52
|
+
reflectionPending: false,
|
|
53
|
+
reflectionRequestedAt: null,
|
|
54
|
+
reflectionToken: null,
|
|
55
|
+
reflectionSignature: null,
|
|
56
|
+
});
|
|
57
|
+
fs.writeFileSync(path.join(dir, 'state', 'zoom-out-report.md'), [
|
|
58
|
+
'## Goal',
|
|
59
|
+
'exercise the breaker',
|
|
60
|
+
'## Failed Attempts',
|
|
61
|
+
'three controlled failures',
|
|
62
|
+
'## Verified Facts',
|
|
63
|
+
'the verification fixture intentionally stays red',
|
|
64
|
+
'## Diagnosis',
|
|
65
|
+
'this is a live enforcement probe',
|
|
66
|
+
'## Decision',
|
|
67
|
+
'RESUME: reproduce the same failure once after reflection',
|
|
68
|
+
'Reflection token: abc123',
|
|
69
|
+
'',
|
|
70
|
+
].join('\n'));
|
|
71
|
+
return dir;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
const valid = makeEvidence();
|
|
76
|
+
let result = verifyEvidence(valid);
|
|
77
|
+
helper.check('31. complete attributed hard-lock evidence passes', result.passed, JSON.stringify(result.checks.filter((entry) => !entry.pass)));
|
|
78
|
+
|
|
79
|
+
const wrongPlugin = makeEvidence();
|
|
80
|
+
const metadataFile = path.join(wrongPlugin, 'metadata.json');
|
|
81
|
+
const metadata = JSON.parse(fs.readFileSync(metadataFile, 'utf8'));
|
|
82
|
+
metadata.installedPluginSha256 = 'b'.repeat(64);
|
|
83
|
+
writeJson(metadataFile, metadata);
|
|
84
|
+
result = verifyEvidence(wrongPlugin);
|
|
85
|
+
helper.check(
|
|
86
|
+
'31. evidence fails when the installed plugin hash differs from the canonical source hash',
|
|
87
|
+
!result.passed && result.checks.some((entry) => entry.name === 'installed plugin is byte-identical to the recorded canonical source' && !entry.pass),
|
|
88
|
+
JSON.stringify(result.checks),
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
const landed = makeEvidence();
|
|
92
|
+
fs.appendFileSync(path.join(landed, 'workspace', 'probe.txt'), `${BLOCKED_MARKER}\n`);
|
|
93
|
+
result = verifyEvidence(landed);
|
|
94
|
+
helper.check(
|
|
95
|
+
'31. negative control fails if the blocked marker reached the filesystem',
|
|
96
|
+
!result.passed && result.checks.some((entry) => entry.name === 'blocked marker did not reach the filesystem' && !entry.pass),
|
|
97
|
+
JSON.stringify(result.checks),
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
const unlocked = makeEvidence();
|
|
101
|
+
const breakerFile = path.join(unlocked, 'state', 'circuit-breaker.json');
|
|
102
|
+
const breaker = JSON.parse(fs.readFileSync(breakerFile, 'utf8'));
|
|
103
|
+
breaker.hardLock = false;
|
|
104
|
+
writeJson(breakerFile, breaker);
|
|
105
|
+
result = verifyEvidence(unlocked);
|
|
106
|
+
helper.check(
|
|
107
|
+
'31. evidence fails without a pre-reset hard-lock snapshot',
|
|
108
|
+
!result.passed && result.checks.some((entry) => entry.name === 'pre-reset breaker snapshot is hard-locked' && !entry.pass),
|
|
109
|
+
JSON.stringify(result.checks),
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
const noAttempt = makeEvidence();
|
|
113
|
+
const transcript = fs.readFileSync(path.join(noAttempt, 'transcript.jsonl'), 'utf8')
|
|
114
|
+
.split(/\r?\n/)
|
|
115
|
+
.filter((line) => !line.includes(BLOCKED_MARKER))
|
|
116
|
+
.join('\n');
|
|
117
|
+
fs.writeFileSync(path.join(noAttempt, 'transcript.jsonl'), transcript);
|
|
118
|
+
result = verifyEvidence(noAttempt);
|
|
119
|
+
helper.check(
|
|
120
|
+
'31. evidence fails when the final blocked edit was never observed as a structured tool attempt',
|
|
121
|
+
!result.passed && result.checks.some((entry) => entry.name === 'structured tool trace contains the final blocked edit attempt' && !entry.pass),
|
|
122
|
+
JSON.stringify(result.checks),
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
const noReflection = makeEvidence();
|
|
126
|
+
fs.rmSync(path.join(noReflection, 'state', 'zoom-out-report.md'));
|
|
127
|
+
result = verifyEvidence(noReflection);
|
|
128
|
+
helper.check(
|
|
129
|
+
'31. evidence fails without the preserved reflection artifact',
|
|
130
|
+
!result.passed && result.checks.some((entry) => entry.name === 'reflection artifact is valid and preserved' && !entry.pass),
|
|
131
|
+
JSON.stringify(result.checks),
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
helper.finish();
|
|
135
|
+
} catch (error) {
|
|
136
|
+
helper.check('31. OpenCode hard-lock live evidence contract', false, error.stack);
|
|
137
|
+
helper.finish();
|
|
138
|
+
}
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const crypto = require('crypto');
|
|
6
|
+
const helper = require('./test-helper');
|
|
7
|
+
const {
|
|
8
|
+
mcnemarExactP,
|
|
9
|
+
prepareArmWorkspace,
|
|
10
|
+
summarizePairs,
|
|
11
|
+
validatePairRecord,
|
|
12
|
+
validateRunConfig,
|
|
13
|
+
} = require('../behavioral-evals/paired-benchmark');
|
|
14
|
+
|
|
15
|
+
console.log('\n[32] paired behavioral benchmark contract...');
|
|
16
|
+
|
|
17
|
+
function stable(value) {
|
|
18
|
+
if (Array.isArray(value)) return value.map(stable);
|
|
19
|
+
if (!value || typeof value !== 'object') return value;
|
|
20
|
+
return Object.fromEntries(Object.keys(value).sort().map((key) => [key, stable(value[key])]));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function hash(value) {
|
|
24
|
+
return crypto.createHash('sha256').update(JSON.stringify(stable(value))).digest('hex');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function skillContract(caseId = 'case-a') {
|
|
28
|
+
return {
|
|
29
|
+
schema_version: 1,
|
|
30
|
+
effect_type: 'skill-text',
|
|
31
|
+
engine: 'opencode',
|
|
32
|
+
requested_model: 'test/model',
|
|
33
|
+
case_id: caseId,
|
|
34
|
+
max_turns: 8,
|
|
35
|
+
loaded_skills: ['tdd'],
|
|
36
|
+
fixture_sha256: 'fixture-hash',
|
|
37
|
+
prompt_sha256: 'prompt-hash',
|
|
38
|
+
rubric_sha256: 'rubric-hash',
|
|
39
|
+
execution_policy: 'opencode-auto',
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function arm(outcome, treatment, overrides = {}) {
|
|
44
|
+
return {
|
|
45
|
+
outcome,
|
|
46
|
+
model_name: 'test/model',
|
|
47
|
+
intervention: {
|
|
48
|
+
skill_text: treatment,
|
|
49
|
+
plugin_enforcement: false,
|
|
50
|
+
},
|
|
51
|
+
loaded_skills: treatment ? ['tdd'] : [],
|
|
52
|
+
plugin_sha256: null,
|
|
53
|
+
plugin_attribution: null,
|
|
54
|
+
cost: treatment ? 2 : 1,
|
|
55
|
+
total_tokens: treatment ? 120 : 100,
|
|
56
|
+
tool_call_count: treatment ? 4 : 3,
|
|
57
|
+
duration_ms: treatment ? 1200 : 1000,
|
|
58
|
+
...overrides,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function skillPair(id, baselineOutcome, treatmentOutcome, overrides = {}) {
|
|
63
|
+
const contract = skillContract(overrides.caseId || id);
|
|
64
|
+
return {
|
|
65
|
+
schema_version: 1,
|
|
66
|
+
id: overrides.caseId || id,
|
|
67
|
+
pair_id: id,
|
|
68
|
+
effect_type: 'skill-text',
|
|
69
|
+
contract,
|
|
70
|
+
contract_sha256: hash(contract),
|
|
71
|
+
arms: {
|
|
72
|
+
baseline: arm(baselineOutcome, false, overrides.baseline || {}),
|
|
73
|
+
treatment: arm(treatmentOutcome, true, overrides.treatment || {}),
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
try {
|
|
79
|
+
const missingThreshold = validateRunConfig({
|
|
80
|
+
effect_type: 'skill-text', engine: 'opencode', model: 'test/model',
|
|
81
|
+
min_effect_pp: NaN, repeats: 1,
|
|
82
|
+
});
|
|
83
|
+
helper.check(
|
|
84
|
+
'32. a paired study cannot start without a predeclared minimum effect',
|
|
85
|
+
missingThreshold.some((problem) => problem.includes('min-effect-pp')),
|
|
86
|
+
missingThreshold.join('; '),
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
const noModel = validateRunConfig({
|
|
90
|
+
effect_type: 'skill-text', engine: 'opencode', model: '',
|
|
91
|
+
min_effect_pp: 10, repeats: 1,
|
|
92
|
+
});
|
|
93
|
+
helper.check(
|
|
94
|
+
'32. an explicit model is required so both arms share the same model contract',
|
|
95
|
+
noModel.some((problem) => problem.includes('explicit --model')),
|
|
96
|
+
noModel.join('; '),
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
const badPluginEngine = validateRunConfig({
|
|
100
|
+
effect_type: 'plugin-enforcement', engine: 'claude', model: 'test/model',
|
|
101
|
+
min_effect_pp: 10, repeats: 1,
|
|
102
|
+
});
|
|
103
|
+
helper.check(
|
|
104
|
+
'32. plugin-enforcement is not generalized beyond the currently attributed OpenCode surface',
|
|
105
|
+
badPluginEngine.some((problem) => problem.includes('opencode only')),
|
|
106
|
+
badPluginEngine.join('; '),
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
const fixtureCase = {
|
|
110
|
+
id: 'workspace-shape',
|
|
111
|
+
discipline: 'tdd',
|
|
112
|
+
fixture: { files: [{ path: 'probe.txt', content: 'baseline\n' }] },
|
|
113
|
+
};
|
|
114
|
+
const skillBaseline = prepareArmWorkspace(fixtureCase, 'skill-text', 'baseline', 'opencode');
|
|
115
|
+
const skillTreatment = prepareArmWorkspace(fixtureCase, 'skill-text', 'treatment', 'opencode');
|
|
116
|
+
helper.check(
|
|
117
|
+
'32. skill-text control contains no Harness skill or plugin',
|
|
118
|
+
!fs.existsSync(path.join(skillBaseline.ws, '.claude', 'skills', 'tdd', 'SKILL.md')) &&
|
|
119
|
+
!fs.existsSync(path.join(skillBaseline.ws, '.opencode', 'plugins', 'harness-enforcement.js')),
|
|
120
|
+
skillBaseline.ws,
|
|
121
|
+
);
|
|
122
|
+
helper.check(
|
|
123
|
+
'32. skill-text treatment installs the named skill without installing hooks/plugin enforcement',
|
|
124
|
+
fs.existsSync(path.join(skillTreatment.ws, '.claude', 'skills', 'tdd', 'SKILL.md')) &&
|
|
125
|
+
!fs.existsSync(path.join(skillTreatment.ws, '.claude', 'settings.json')) &&
|
|
126
|
+
!fs.existsSync(path.join(skillTreatment.ws, '.opencode', 'plugins', 'harness-enforcement.js')),
|
|
127
|
+
skillTreatment.ws,
|
|
128
|
+
);
|
|
129
|
+
fs.rmSync(skillBaseline.ws, { recursive: true, force: true });
|
|
130
|
+
fs.rmSync(skillTreatment.ws, { recursive: true, force: true });
|
|
131
|
+
|
|
132
|
+
const pluginBaseline = prepareArmWorkspace(fixtureCase, 'plugin-enforcement', 'baseline', 'opencode');
|
|
133
|
+
const pluginTreatment = prepareArmWorkspace(fixtureCase, 'plugin-enforcement', 'treatment', 'opencode');
|
|
134
|
+
helper.check(
|
|
135
|
+
'32. plugin experiment holds skill text constant and changes only enforcement installation',
|
|
136
|
+
fs.existsSync(path.join(pluginBaseline.ws, '.claude', 'skills', 'tdd', 'SKILL.md')) &&
|
|
137
|
+
fs.existsSync(path.join(pluginTreatment.ws, '.claude', 'skills', 'tdd', 'SKILL.md')) &&
|
|
138
|
+
!fs.existsSync(path.join(pluginBaseline.ws, '.opencode', 'plugins', 'harness-enforcement.js')) &&
|
|
139
|
+
fs.existsSync(path.join(pluginTreatment.ws, '.opencode', 'plugins', 'harness-enforcement.js')),
|
|
140
|
+
JSON.stringify({ baseline: pluginBaseline.ws, treatment: pluginTreatment.ws }),
|
|
141
|
+
);
|
|
142
|
+
fs.rmSync(pluginBaseline.ws, { recursive: true, force: true });
|
|
143
|
+
fs.rmSync(pluginTreatment.ws, { recursive: true, force: true });
|
|
144
|
+
|
|
145
|
+
const validSkillPair = skillPair('p1', 'fail', 'pass');
|
|
146
|
+
helper.check('32. a correctly isolated skill-text pair is includable', validatePairRecord(validSkillPair).included, JSON.stringify(validatePairRecord(validSkillPair)));
|
|
147
|
+
|
|
148
|
+
const modelMismatch = skillPair('model-mismatch', 'fail', 'pass', {
|
|
149
|
+
treatment: { model_name: 'other/model' },
|
|
150
|
+
});
|
|
151
|
+
helper.check(
|
|
152
|
+
'32. actual model mismatch excludes the pair instead of counting it as behavior',
|
|
153
|
+
!validatePairRecord(modelMismatch).included && validatePairRecord(modelMismatch).reason === 'actual-model-mismatch',
|
|
154
|
+
JSON.stringify(validatePairRecord(modelMismatch)),
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
const pluginContract = {
|
|
158
|
+
schema_version: 1,
|
|
159
|
+
effect_type: 'plugin-enforcement',
|
|
160
|
+
engine: 'opencode',
|
|
161
|
+
requested_model: 'test/model',
|
|
162
|
+
case_id: 'plugin-case',
|
|
163
|
+
max_turns: 8,
|
|
164
|
+
loaded_skills: ['tdd'],
|
|
165
|
+
fixture_sha256: 'fixture-hash',
|
|
166
|
+
prompt_sha256: 'prompt-hash',
|
|
167
|
+
rubric_sha256: 'rubric-hash',
|
|
168
|
+
execution_policy: 'opencode-auto',
|
|
169
|
+
};
|
|
170
|
+
const pluginPair = {
|
|
171
|
+
id: 'plugin-case',
|
|
172
|
+
pair_id: 'plugin-pair',
|
|
173
|
+
effect_type: 'plugin-enforcement',
|
|
174
|
+
contract: pluginContract,
|
|
175
|
+
contract_sha256: hash(pluginContract),
|
|
176
|
+
preflight: { passed: true, plugin_sha256: 'plugin-hash' },
|
|
177
|
+
arms: {
|
|
178
|
+
baseline: {
|
|
179
|
+
...arm('fail', true),
|
|
180
|
+
intervention: { skill_text: true, plugin_enforcement: false },
|
|
181
|
+
loaded_skills: ['tdd'],
|
|
182
|
+
},
|
|
183
|
+
treatment: {
|
|
184
|
+
...arm('pass', true),
|
|
185
|
+
intervention: { skill_text: true, plugin_enforcement: true },
|
|
186
|
+
loaded_skills: ['tdd'],
|
|
187
|
+
plugin_sha256: 'plugin-hash',
|
|
188
|
+
plugin_attribution: { fired: true, state_files: ['workspaces/x/state/sessions/y/edit-state.json'] },
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
};
|
|
192
|
+
helper.check(
|
|
193
|
+
'32. plugin pair is includable only when preflight, hash, constant skill text, and per-arm attribution agree',
|
|
194
|
+
validatePairRecord(pluginPair).included,
|
|
195
|
+
JSON.stringify(validatePairRecord(pluginPair)),
|
|
196
|
+
);
|
|
197
|
+
const unattributedPlugin = JSON.parse(JSON.stringify(pluginPair));
|
|
198
|
+
unattributedPlugin.pair_id = 'plugin-unattributed';
|
|
199
|
+
unattributedPlugin.arms.treatment.plugin_attribution.fired = false;
|
|
200
|
+
helper.check(
|
|
201
|
+
'32. missing live plugin attribution is infrastructure/inconclusive, not a behavioral result',
|
|
202
|
+
!validatePairRecord(unattributedPlugin).included && validatePairRecord(unattributedPlugin).reason === 'plugin-attribution-missing',
|
|
203
|
+
JSON.stringify(validatePairRecord(unattributedPlugin)),
|
|
204
|
+
);
|
|
205
|
+
|
|
206
|
+
const records = [
|
|
207
|
+
skillPair('a-r1', 'fail', 'pass', { caseId: 'a' }),
|
|
208
|
+
skillPair('a-r2', 'fail', 'pass', { caseId: 'a' }),
|
|
209
|
+
skillPair('b-r1', 'pass', 'fail', { caseId: 'b' }),
|
|
210
|
+
skillPair('c-r1', 'pass', 'pass', { caseId: 'c' }),
|
|
211
|
+
skillPair('infra-r1', 'pass', 'session-error', { caseId: 'infra' }),
|
|
212
|
+
];
|
|
213
|
+
const summary = summarizePairs(records, 10);
|
|
214
|
+
helper.check(
|
|
215
|
+
'32. summary excludes infrastructure outcomes and reports paired transitions',
|
|
216
|
+
summary.requested_pairs === 5 && summary.included_pairs === 4 && summary.excluded_pairs === 1 &&
|
|
217
|
+
summary.transitions['fail->pass'] === 2 && summary.transitions['pass->fail'] === 1 &&
|
|
218
|
+
summary.transitions['pass->pass'] === 1 && summary.transitions['fail->fail'] === 0,
|
|
219
|
+
JSON.stringify(summary),
|
|
220
|
+
);
|
|
221
|
+
helper.check(
|
|
222
|
+
'32. paired effect is derived from within-pair transitions and carries a deterministic uncertainty interval',
|
|
223
|
+
summary.paired_effect_pp === 25 && Array.isArray(summary.paired_effect_ci95_pp) && summary.paired_effect_ci95_pp.length === 2,
|
|
224
|
+
JSON.stringify(summary),
|
|
225
|
+
);
|
|
226
|
+
helper.check(
|
|
227
|
+
'32. repeated runs remain separate samples and expose per-case variance instead of overwriting',
|
|
228
|
+
summary.repeat_variance.a.repeats === 2 && summary.repeat_variance.a.paired_difference_variance === 0,
|
|
229
|
+
JSON.stringify(summary.repeat_variance),
|
|
230
|
+
);
|
|
231
|
+
helper.check(
|
|
232
|
+
'32. cost and execution overhead are reported separately from correctness',
|
|
233
|
+
summary.cost_and_execution_overhead.cost_delta.mean === 1 &&
|
|
234
|
+
summary.cost_and_execution_overhead.token_delta.mean === 20 &&
|
|
235
|
+
summary.cost_and_execution_overhead.tool_call_delta.mean === 1 &&
|
|
236
|
+
summary.cost_and_execution_overhead.duration_ms_delta.mean === 200,
|
|
237
|
+
JSON.stringify(summary.cost_and_execution_overhead),
|
|
238
|
+
);
|
|
239
|
+
helper.check(
|
|
240
|
+
'32. exact discordant-pair statistic is available without turning it into an unpaired pass-rate verdict',
|
|
241
|
+
mcnemarExactP(2, 1) === 1 && summary.mcnemar_exact_p === 1,
|
|
242
|
+
JSON.stringify({ direct: mcnemarExactP(2, 1), summary: summary.mcnemar_exact_p }),
|
|
243
|
+
);
|
|
244
|
+
helper.check(
|
|
245
|
+
'32. the predeclared practical threshold is retained in the summary decision contract',
|
|
246
|
+
summary.decision.min_effect_pp === 10 && /predeclared/i.test(summary.decision.rule),
|
|
247
|
+
JSON.stringify(summary.decision),
|
|
248
|
+
);
|
|
249
|
+
|
|
250
|
+
helper.finish();
|
|
251
|
+
} catch (error) {
|
|
252
|
+
helper.check('32. paired behavioral benchmark contract', false, error.stack);
|
|
253
|
+
helper.finish();
|
|
254
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "harness-everything",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Harness OS: An Orchestrated Agent Operating System for AI-driven Development",
|
|
5
5
|
"main": "harness-everything/scripts/bootstrap.js",
|
|
6
6
|
"bin": {
|
|
@@ -40,6 +40,9 @@
|
|
|
40
40
|
"eval:behavioral": "node behavioral-evals/run.js run",
|
|
41
41
|
"eval:behavioral:validate": "node behavioral-evals/run.js validate",
|
|
42
42
|
"eval:behavioral:plugin": "node behavioral-evals/run-with-plugin.js run",
|
|
43
|
+
"eval:opencode:hardlock-live": "node behavioral-evals/opencode-hardlock-live.js run",
|
|
44
|
+
"eval:paired": "node behavioral-evals/paired-benchmark.js run",
|
|
45
|
+
"eval:paired:summarize": "node behavioral-evals/paired-benchmark.js summarize",
|
|
43
46
|
"test:ab": "node ci/ab-test-harness.js validate",
|
|
44
47
|
"test:ab:run": "node ci/ab-test-harness.js run",
|
|
45
48
|
"harness:reset": "node hooks/scripts/reset-circuit-breaker.js",
|
|
@@ -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.6.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",
|