harness-everything 0.2.1 โ†’ 0.2.2

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 (70) hide show
  1. package/README.md +1 -1
  2. package/build-multi-agent-system/SKILL.md +68 -68
  3. package/create-agent-launcher/SKILL.md +48 -48
  4. package/docs/architecture.md +2 -2
  5. package/docs/workflows/build-multi-agent-system.md +62 -62
  6. package/docs/workflows/create-agent-launcher.md +62 -62
  7. package/docs/workflows/environment-detection.md +63 -63
  8. package/docs/workflows/eval-harness.md +57 -57
  9. package/docs/workflows/fable-discipline.md +59 -59
  10. package/docs/workflows/fable-mode.md +32 -32
  11. package/docs/workflows/git-commit.md +62 -62
  12. package/docs/workflows/grill-me.md +62 -62
  13. package/docs/workflows/grill-with-docs.md +62 -62
  14. package/docs/workflows/improve-codebase-architecture.md +60 -60
  15. package/docs/workflows/repo-docs.md +59 -59
  16. package/docs/workflows/rewrite-commits.md +60 -60
  17. package/docs/workflows/security-review.md +58 -58
  18. package/docs/workflows/self-evolve.md +59 -59
  19. package/docs/workflows/tdd.md +39 -39
  20. package/docs/workflows/todo-driven-workflow.md +36 -36
  21. package/docs/workflows/using-git-worktrees.md +63 -63
  22. package/docs/workflows/verification-loop.md +69 -69
  23. package/docs/workflows/verify-before-claim.md +60 -60
  24. package/docs/workflows/zoom-out.md +62 -62
  25. package/environment-detection/SKILL.md +77 -77
  26. package/eval-framework/behavioral-test.js +105 -105
  27. package/eval-framework/mechanism-test.js +251 -251
  28. package/eval-harness/SKILL.md +59 -59
  29. package/fable-discipline/SKILL.md +38 -38
  30. package/fable-mode/SKILL.md +51 -51
  31. package/git-commit/SKILL.md +55 -55
  32. package/grill-me/SKILL.md +36 -36
  33. package/grill-with-docs/SKILL.md +99 -99
  34. package/harness-everything/SKILL.md +141 -141
  35. package/harness-everything/examples/README.md +9 -9
  36. package/harness-everything/examples/todo-workflow.md +22 -22
  37. package/harness-everything/scripts/todo-cli.js +157 -157
  38. package/harness-everything/scripts/verify-gate.js +31 -31
  39. package/hooks/scripts/atomic-commit-check.js +68 -68
  40. package/hooks/scripts/context-compact.js +114 -114
  41. package/hooks/scripts/lib/platforms/claude.js +132 -42
  42. package/hooks/scripts/lib/platforms/codex.js +96 -46
  43. package/hooks/scripts/lib/platforms/continue.js +73 -41
  44. package/hooks/scripts/lib/platforms/copilot.js +91 -41
  45. package/hooks/scripts/lib/platforms/cursor.js +71 -41
  46. package/hooks/scripts/lib/platforms/hermes.js +25 -0
  47. package/hooks/scripts/rule-of-3.js +176 -176
  48. package/improve-codebase-architecture/SKILL.md +44 -44
  49. package/install-cognitive-os/SKILL.md +95 -95
  50. package/package.json +1 -1
  51. package/repo-docs/SKILL.md +45 -45
  52. package/rewrite-commits/SKILL.md +32 -32
  53. package/scripts/installer.js +57 -200
  54. package/scripts/lib/advisory-text.js +163 -163
  55. package/scripts/lib/claude-hooks.js +71 -71
  56. package/scripts/lib/manifest.js +82 -82
  57. package/scripts/lib/prompts.js +241 -241
  58. package/scripts/lib/skills.js +174 -172
  59. package/scripts/lib/workspace.js +28 -28
  60. package/security-review/SKILL.md +510 -510
  61. package/self-evolve/SKILL.md +54 -54
  62. package/skill-creator/SKILL.md +91 -91
  63. package/skill-creator/references/testing-workflow.md +32 -32
  64. package/skill-style/SKILL.md +48 -48
  65. package/tdd/SKILL.md +53 -53
  66. package/todo-driven-workflow/SKILL.md +54 -54
  67. package/using-git-worktrees/SKILL.md +161 -161
  68. package/verification-loop/SKILL.md +138 -138
  69. package/verify-before-claim/SKILL.md +86 -86
  70. package/zoom-out/SKILL.md +90 -90
@@ -1,251 +1,251 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Harness Mechanism Test Suite (Claude Code hook contract)
4
- * Automates VERIFICATION.md Section 2 (mechanism check) so it runs on every
5
- * `npm test` instead of only when a human copy-pastes the recipes by hand.
6
- * That manual gap is exactly what let three independent 2026-07-23 audit
7
- * reports (see docs/reports/) misdiagnose working hooks as broken: they
8
- * piped JSON via `echo '...' | node script.js` in a Windows Git Bash shell,
9
- * which mangles stdin/TTY state and produced false negatives. This suite
10
- * uses execSync's `input` option instead (the same technique already proven
11
- * reliable in runner.js and behavioral-test.js) so it is a faithful,
12
- * cross-platform re-run of the exact payloads VERIFICATION.md documents.
13
- *
14
- * Each hook resolves its state directory via detectActivePlatform(), which
15
- * defaults to 'copilot' under a VS Code integrated terminal (TERM_PROGRAM=
16
- * vscode) unless CLAUDE is set - so every child process below is spawned
17
- * with CLAUDE=1 to force the Claude Code state path regardless of the host
18
- * running this test.
19
- *
20
- * All state is written under a dedicated, never-real session id so this
21
- * suite can never collide with or clobber an actual Claude Code session's
22
- * breaker/handoff state. The session directory (and any repo-root temp
23
- * files created along the way) is removed on exit, success or failure alike.
24
- */
25
- const { execSync } = require('child_process');
26
- const fs = require('fs');
27
- const path = require('path');
28
-
29
- process.env.CLAUDE = '1'; // so our own getSessionDir() calls resolve like the children's will
30
-
31
- const { getWorkspaceRoot, getSessionDir } = require('../hooks/scripts/lib/harness-state');
32
-
33
- const root = getWorkspaceRoot();
34
- const hooksDir = path.join(root, 'hooks', 'scripts');
35
- const SESSION_ID = '__mechanism_test__';
36
- const sessionDir = getSessionDir(root, SESSION_ID);
37
-
38
- console.log('=== ๐Ÿ”ง Harness Mechanism Test Suite (VERIFICATION.md ยง2) ===');
39
-
40
- const tempFiles = [];
41
- let failures = 0;
42
-
43
- function check(name, condition, detail) {
44
- if (condition) {
45
- console.log(`โœ… ${name}`);
46
- } else {
47
- console.error(`โŒ ${name}`);
48
- if (detail) console.error(` ${detail}`);
49
- failures++;
50
- }
51
- }
52
-
53
- function runHook(scriptName, payload, extraEnv) {
54
- const scriptPath = path.join(hooksDir, scriptName);
55
- try {
56
- const stdout = execSync(`node "${scriptPath}"`, {
57
- encoding: 'utf8',
58
- input: payload === null ? '' : JSON.stringify(payload),
59
- env: { ...process.env, ...extraEnv },
60
- });
61
- return { code: 0, stdout, stderr: '' };
62
- } catch (err) {
63
- return { code: err.status, stdout: err.stdout || '', stderr: err.stderr || '' };
64
- }
65
- }
66
-
67
- function writeState(file, obj) {
68
- fs.writeFileSync(path.join(sessionDir, file), JSON.stringify(obj, null, 2), 'utf8');
69
- }
70
- function readState(file) {
71
- return JSON.parse(fs.readFileSync(path.join(sessionDir, file), 'utf8'));
72
- }
73
- function stateExists(file) {
74
- return fs.existsSync(path.join(sessionDir, file));
75
- }
76
-
77
- // Registers a repo-root temp file for guaranteed cleanup even if an
78
- // assertion throws or the process is killed mid-suite.
79
- function tempFile(name) {
80
- const p = path.join(root, name);
81
- tempFiles.push(p);
82
- return p;
83
- }
84
-
85
- process.on('exit', () => {
86
- for (const f of tempFiles) {
87
- try { if (fs.existsSync(f)) fs.unlinkSync(f); } catch (e) { /* best-effort */ }
88
- }
89
- try { fs.rmSync(sessionDir, { recursive: true, force: true }); } catch (e) { /* best-effort */ }
90
- });
91
-
92
- // ---------------------------------------------------------------------------
93
- // 2a. Rule of 3 circuit breaker trips, releases via zoom-out report, and
94
- // hard-locks on a repeat trip of the same signature.
95
- // ---------------------------------------------------------------------------
96
- console.log('\n[2a] Rule of 3 circuit breaker...');
97
-
98
- writeState('rule-of-3-state.json', { count: 3, lastHash: 'mech-test', zoomOutResolved: false });
99
- const tripResult = runHook('rule-of-3.js', { session_id: SESSION_ID });
100
- check(
101
- '2a. Trips at count=3 (exit=2, CRITICAL banner)',
102
- tripResult.code === 2 && tripResult.stderr.includes('RULE OF 3 CIRCUIT BREAKER TRIGGERED'),
103
- `Got exit=${tripResult.code}, stderr="${tripResult.stderr.slice(0, 200)}"`
104
- );
105
-
106
- writeState('rule-of-3-state.json', {
107
- count: 3, lastHash: 'mech-test', zoomOutResolved: false, lastFailureAt: 0, zoomOutCycles: 0,
108
- });
109
- fs.writeFileSync(
110
- path.join(sessionDir, 'zoom-out-report.md'),
111
- '## Goal\nx\n## Failed Attempts\nx\n## Verified Facts\nx\n## Diagnosis\nx\n## Decision\nRESUME: new approach\n',
112
- 'utf8'
113
- );
114
- const releaseResult = runHook('rule-of-3.js', { session_id: SESSION_ID });
115
- const releasedState = readState('rule-of-3-state.json');
116
- check(
117
- '2a-bis. Valid zoom-out report releases the breaker (exit=0, count reset)',
118
- releaseResult.code === 0 &&
119
- releaseResult.stdout.includes('breaker released') &&
120
- releasedState.count === 0 &&
121
- releasedState.zoomOutResolved === true &&
122
- releasedState.zoomOutCycles === 1,
123
- `Got exit=${releaseResult.code}, state=${JSON.stringify(releasedState)}`
124
- );
125
-
126
- writeState('rule-of-3-state.json', {
127
- count: 3, lastHash: 'mech-test', zoomOutResolved: false,
128
- lastFailureAt: Date.now() + 60000, zoomOutCycles: 1,
129
- });
130
- const hardLockResult = runHook('rule-of-3.js', { session_id: SESSION_ID });
131
- check(
132
- '2a-ter. Second trip on same signature hard-locks (exit=2, repeat trip)',
133
- hardLockResult.code === 2 && hardLockResult.stderr.includes('repeat trip - hard lock'),
134
- `Got exit=${hardLockResult.code}, stderr="${hardLockResult.stderr.slice(0, 200)}"`
135
- );
136
-
137
- // ---------------------------------------------------------------------------
138
- // 2b. Boundary guard blocks an oversized Read
139
- // ---------------------------------------------------------------------------
140
- console.log('\n[2b] Boundary guard...');
141
-
142
- const bigFile = tempFile('.mechanism-test-big.tmp');
143
- fs.writeFileSync(bigFile, 'x'.repeat(600 * 1024));
144
- const boundaryResult = runHook('boundary-guard.js', { tool_name: 'Read', tool_input: { file_path: bigFile } });
145
- check(
146
- '2b. Blocks a 600KB Read without limit/offset (exit=2, BLOCKED)',
147
- boundaryResult.code === 2 && boundaryResult.stderr.includes('[Boundary Guard] BLOCKED'),
148
- `Got exit=${boundaryResult.code}, stderr="${boundaryResult.stderr.slice(0, 200)}"`
149
- );
150
- fs.unlinkSync(bigFile);
151
-
152
- // ---------------------------------------------------------------------------
153
- // 2c. State persistence (WAL) records a failure, then clears it on success
154
- // ---------------------------------------------------------------------------
155
- console.log('\n[2c] State persistence (WAL)...');
156
-
157
- runHook('state-persist.js', {
158
- session_id: SESSION_ID,
159
- tool_name: 'Bash',
160
- tool_response: { stdout: '', stderr: 'npm ERR! mech-test failure' },
161
- });
162
- const failedHandoff = readState('handoff-state.json');
163
- check(
164
- '2c. Failing Bash call is recorded as status=failed',
165
- failedHandoff.status === 'failed' && failedHandoff.errorSummary.includes('mech-test failure'),
166
- `Got ${JSON.stringify(failedHandoff)}`
167
- );
168
-
169
- runHook('state-persist.js', {
170
- session_id: SESSION_ID,
171
- tool_name: 'Bash',
172
- tool_response: { stdout: 'ok', exitCode: 0 },
173
- });
174
- const resolvedHandoff = readState('handoff-state.json');
175
- check(
176
- '2c. A subsequent successful command clears status back to idle',
177
- resolvedHandoff.status === 'idle' && !!resolvedHandoff.lastResolved,
178
- `Got ${JSON.stringify(resolvedHandoff)}`
179
- );
180
-
181
- // ---------------------------------------------------------------------------
182
- // 2d. Fact-audit reminder reaches the agent via tier-router.js stdin
183
- // ---------------------------------------------------------------------------
184
- console.log('\n[2d] Fact-audit reminder...');
185
-
186
- const tierRouterPath = path.join(root, 'harness-everything', 'scripts', 'tier-router.js');
187
- const factAuditOut = execSync(`node "${tierRouterPath}"`, {
188
- encoding: 'utf8',
189
- input: JSON.stringify({ prompt: 'what exit code does this hook use by default and is it documented' }),
190
- });
191
- check(
192
- '2d. tier-router.js reads {"prompt":...} from stdin and emits FACT-AUDIT REMINDER',
193
- factAuditOut.includes('FACT-AUDIT REMINDER'),
194
- `Output was:\n${factAuditOut.slice(0, 300)}`
195
- );
196
-
197
- // ---------------------------------------------------------------------------
198
- // 2e. Subagent scope guard catches an out-of-scope file change
199
- // ---------------------------------------------------------------------------
200
- console.log('\n[2e] Subagent scope guard...');
201
-
202
- runHook('subagent-scope-guard.js', {
203
- session_id: SESSION_ID, tool_name: 'Task', hook_event_name: 'PreToolUse', tool_input: {},
204
- });
205
- const scopeFile = tempFile('.mechanism-test-scope.tmp');
206
- fs.writeFileSync(scopeFile, 'unexpected change');
207
- const scopeResult = runHook('subagent-scope-guard.js', {
208
- session_id: SESSION_ID, tool_name: 'Task', hook_event_name: 'PostToolUse', tool_input: {},
209
- });
210
- check(
211
- '2e. Flags the newly-created file after a Task burst (exit=2, lists filename)',
212
- scopeResult.code === 2 &&
213
- scopeResult.stderr.includes('Subagent Scope Guard') &&
214
- scopeResult.stderr.includes(path.basename(scopeFile)),
215
- `Got exit=${scopeResult.code}, stderr="${scopeResult.stderr.slice(0, 300)}"`
216
- );
217
- fs.unlinkSync(scopeFile);
218
-
219
- // ---------------------------------------------------------------------------
220
- // 2f. Stop gate bounces an unverified-edit stop exactly once
221
- // ---------------------------------------------------------------------------
222
- console.log('\n[2f] Stop gate...');
223
-
224
- writeState('handoff-state.json', { status: 'idle', lastEditAt: Date.now(), lastVerifyAt: 0 });
225
- const dirtyFile = tempFile('.mechanism-test-dirty.tmp');
226
- fs.writeFileSync(dirtyFile, 'dirty');
227
- const firstStop = runHook('stop-gate.js', { session_id: SESSION_ID });
228
- check(
229
- '2f. First stop after an unverified edit bounces (exit=2)',
230
- firstStop.code === 2 && firstStop.stderr.includes('[Stop Gate]'),
231
- `Got exit=${firstStop.code}, stderr="${firstStop.stderr.slice(0, 200)}"`
232
- );
233
- const secondStop = runHook('stop-gate.js', { session_id: SESSION_ID });
234
- check(
235
- '2f. Same edit batch does not bounce twice (exit=0)',
236
- secondStop.code === 0,
237
- `Got exit=${secondStop.code}`
238
- );
239
- fs.unlinkSync(dirtyFile);
240
-
241
- // ---------------------------------------------------------------------------
242
- console.log('\n=================================================');
243
- if (failures > 0) {
244
- console.error(` โŒ ${failures} mechanism check(s) FAILED.`);
245
- console.log('=================================================');
246
- process.exit(1);
247
- } else {
248
- console.log(' ๐ŸŽ‰ All VERIFICATION.md ยง2 mechanism checks passed.');
249
- console.log('=================================================');
250
- process.exit(0);
251
- }
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Harness Mechanism Test Suite (Claude Code hook contract)
4
+ * Automates VERIFICATION.md Section 2 (mechanism check) so it runs on every
5
+ * `npm test` instead of only when a human copy-pastes the recipes by hand.
6
+ * That manual gap is exactly what let three independent 2026-07-23 audit
7
+ * reports (see docs/reports/) misdiagnose working hooks as broken: they
8
+ * piped JSON via `echo '...' | node script.js` in a Windows Git Bash shell,
9
+ * which mangles stdin/TTY state and produced false negatives. This suite
10
+ * uses execSync's `input` option instead (the same technique already proven
11
+ * reliable in runner.js and behavioral-test.js) so it is a faithful,
12
+ * cross-platform re-run of the exact payloads VERIFICATION.md documents.
13
+ *
14
+ * Each hook resolves its state directory via detectActivePlatform(), which
15
+ * defaults to 'copilot' under a VS Code integrated terminal (TERM_PROGRAM=
16
+ * vscode) unless CLAUDE is set - so every child process below is spawned
17
+ * with CLAUDE=1 to force the Claude Code state path regardless of the host
18
+ * running this test.
19
+ *
20
+ * All state is written under a dedicated, never-real session id so this
21
+ * suite can never collide with or clobber an actual Claude Code session's
22
+ * breaker/handoff state. The session directory (and any repo-root temp
23
+ * files created along the way) is removed on exit, success or failure alike.
24
+ */
25
+ const { execSync } = require('child_process');
26
+ const fs = require('fs');
27
+ const path = require('path');
28
+
29
+ process.env.CLAUDE = '1'; // so our own getSessionDir() calls resolve like the children's will
30
+
31
+ const { getWorkspaceRoot, getSessionDir } = require('../hooks/scripts/lib/harness-state');
32
+
33
+ const root = getWorkspaceRoot();
34
+ const hooksDir = path.join(root, 'hooks', 'scripts');
35
+ const SESSION_ID = '__mechanism_test__';
36
+ const sessionDir = getSessionDir(root, SESSION_ID);
37
+
38
+ console.log('=== ๐Ÿ”ง Harness Mechanism Test Suite (VERIFICATION.md ยง2) ===');
39
+
40
+ const tempFiles = [];
41
+ let failures = 0;
42
+
43
+ function check(name, condition, detail) {
44
+ if (condition) {
45
+ console.log(`โœ… ${name}`);
46
+ } else {
47
+ console.error(`โŒ ${name}`);
48
+ if (detail) console.error(` ${detail}`);
49
+ failures++;
50
+ }
51
+ }
52
+
53
+ function runHook(scriptName, payload, extraEnv) {
54
+ const scriptPath = path.join(hooksDir, scriptName);
55
+ try {
56
+ const stdout = execSync(`node "${scriptPath}"`, {
57
+ encoding: 'utf8',
58
+ input: payload === null ? '' : JSON.stringify(payload),
59
+ env: { ...process.env, ...extraEnv },
60
+ });
61
+ return { code: 0, stdout, stderr: '' };
62
+ } catch (err) {
63
+ return { code: err.status, stdout: err.stdout || '', stderr: err.stderr || '' };
64
+ }
65
+ }
66
+
67
+ function writeState(file, obj) {
68
+ fs.writeFileSync(path.join(sessionDir, file), JSON.stringify(obj, null, 2), 'utf8');
69
+ }
70
+ function readState(file) {
71
+ return JSON.parse(fs.readFileSync(path.join(sessionDir, file), 'utf8'));
72
+ }
73
+ function stateExists(file) {
74
+ return fs.existsSync(path.join(sessionDir, file));
75
+ }
76
+
77
+ // Registers a repo-root temp file for guaranteed cleanup even if an
78
+ // assertion throws or the process is killed mid-suite.
79
+ function tempFile(name) {
80
+ const p = path.join(root, name);
81
+ tempFiles.push(p);
82
+ return p;
83
+ }
84
+
85
+ process.on('exit', () => {
86
+ for (const f of tempFiles) {
87
+ try { if (fs.existsSync(f)) fs.unlinkSync(f); } catch (e) { /* best-effort */ }
88
+ }
89
+ try { fs.rmSync(sessionDir, { recursive: true, force: true }); } catch (e) { /* best-effort */ }
90
+ });
91
+
92
+ // ---------------------------------------------------------------------------
93
+ // 2a. Rule of 3 circuit breaker trips, releases via zoom-out report, and
94
+ // hard-locks on a repeat trip of the same signature.
95
+ // ---------------------------------------------------------------------------
96
+ console.log('\n[2a] Rule of 3 circuit breaker...');
97
+
98
+ writeState('rule-of-3-state.json', { count: 3, lastHash: 'mech-test', zoomOutResolved: false });
99
+ const tripResult = runHook('rule-of-3.js', { session_id: SESSION_ID });
100
+ check(
101
+ '2a. Trips at count=3 (exit=2, CRITICAL banner)',
102
+ tripResult.code === 2 && tripResult.stderr.includes('RULE OF 3 CIRCUIT BREAKER TRIGGERED'),
103
+ `Got exit=${tripResult.code}, stderr="${tripResult.stderr.slice(0, 200)}"`
104
+ );
105
+
106
+ writeState('rule-of-3-state.json', {
107
+ count: 3, lastHash: 'mech-test', zoomOutResolved: false, lastFailureAt: 0, zoomOutCycles: 0,
108
+ });
109
+ fs.writeFileSync(
110
+ path.join(sessionDir, 'zoom-out-report.md'),
111
+ '## Goal\nx\n## Failed Attempts\nx\n## Verified Facts\nx\n## Diagnosis\nx\n## Decision\nRESUME: new approach\n',
112
+ 'utf8'
113
+ );
114
+ const releaseResult = runHook('rule-of-3.js', { session_id: SESSION_ID });
115
+ const releasedState = readState('rule-of-3-state.json');
116
+ check(
117
+ '2a-bis. Valid zoom-out report releases the breaker (exit=0, count reset)',
118
+ releaseResult.code === 0 &&
119
+ releaseResult.stdout.includes('breaker released') &&
120
+ releasedState.count === 0 &&
121
+ releasedState.zoomOutResolved === true &&
122
+ releasedState.zoomOutCycles === 1,
123
+ `Got exit=${releaseResult.code}, state=${JSON.stringify(releasedState)}`
124
+ );
125
+
126
+ writeState('rule-of-3-state.json', {
127
+ count: 3, lastHash: 'mech-test', zoomOutResolved: false,
128
+ lastFailureAt: Date.now() + 60000, zoomOutCycles: 1,
129
+ });
130
+ const hardLockResult = runHook('rule-of-3.js', { session_id: SESSION_ID });
131
+ check(
132
+ '2a-ter. Second trip on same signature hard-locks (exit=2, repeat trip)',
133
+ hardLockResult.code === 2 && hardLockResult.stderr.includes('repeat trip - hard lock'),
134
+ `Got exit=${hardLockResult.code}, stderr="${hardLockResult.stderr.slice(0, 200)}"`
135
+ );
136
+
137
+ // ---------------------------------------------------------------------------
138
+ // 2b. Boundary guard blocks an oversized Read
139
+ // ---------------------------------------------------------------------------
140
+ console.log('\n[2b] Boundary guard...');
141
+
142
+ const bigFile = tempFile('.mechanism-test-big.tmp');
143
+ fs.writeFileSync(bigFile, 'x'.repeat(600 * 1024));
144
+ const boundaryResult = runHook('boundary-guard.js', { tool_name: 'Read', tool_input: { file_path: bigFile } });
145
+ check(
146
+ '2b. Blocks a 600KB Read without limit/offset (exit=2, BLOCKED)',
147
+ boundaryResult.code === 2 && boundaryResult.stderr.includes('[Boundary Guard] BLOCKED'),
148
+ `Got exit=${boundaryResult.code}, stderr="${boundaryResult.stderr.slice(0, 200)}"`
149
+ );
150
+ fs.unlinkSync(bigFile);
151
+
152
+ // ---------------------------------------------------------------------------
153
+ // 2c. State persistence (WAL) records a failure, then clears it on success
154
+ // ---------------------------------------------------------------------------
155
+ console.log('\n[2c] State persistence (WAL)...');
156
+
157
+ runHook('state-persist.js', {
158
+ session_id: SESSION_ID,
159
+ tool_name: 'Bash',
160
+ tool_response: { stdout: '', stderr: 'npm ERR! mech-test failure' },
161
+ });
162
+ const failedHandoff = readState('handoff-state.json');
163
+ check(
164
+ '2c. Failing Bash call is recorded as status=failed',
165
+ failedHandoff.status === 'failed' && failedHandoff.errorSummary.includes('mech-test failure'),
166
+ `Got ${JSON.stringify(failedHandoff)}`
167
+ );
168
+
169
+ runHook('state-persist.js', {
170
+ session_id: SESSION_ID,
171
+ tool_name: 'Bash',
172
+ tool_response: { stdout: 'ok', exitCode: 0 },
173
+ });
174
+ const resolvedHandoff = readState('handoff-state.json');
175
+ check(
176
+ '2c. A subsequent successful command clears status back to idle',
177
+ resolvedHandoff.status === 'idle' && !!resolvedHandoff.lastResolved,
178
+ `Got ${JSON.stringify(resolvedHandoff)}`
179
+ );
180
+
181
+ // ---------------------------------------------------------------------------
182
+ // 2d. Fact-audit reminder reaches the agent via tier-router.js stdin
183
+ // ---------------------------------------------------------------------------
184
+ console.log('\n[2d] Fact-audit reminder...');
185
+
186
+ const tierRouterPath = path.join(root, 'harness-everything', 'scripts', 'tier-router.js');
187
+ const factAuditOut = execSync(`node "${tierRouterPath}"`, {
188
+ encoding: 'utf8',
189
+ input: JSON.stringify({ prompt: 'what exit code does this hook use by default and is it documented' }),
190
+ });
191
+ check(
192
+ '2d. tier-router.js reads {"prompt":...} from stdin and emits FACT-AUDIT REMINDER',
193
+ factAuditOut.includes('FACT-AUDIT REMINDER'),
194
+ `Output was:\n${factAuditOut.slice(0, 300)}`
195
+ );
196
+
197
+ // ---------------------------------------------------------------------------
198
+ // 2e. Subagent scope guard catches an out-of-scope file change
199
+ // ---------------------------------------------------------------------------
200
+ console.log('\n[2e] Subagent scope guard...');
201
+
202
+ runHook('subagent-scope-guard.js', {
203
+ session_id: SESSION_ID, tool_name: 'Task', hook_event_name: 'PreToolUse', tool_input: {},
204
+ });
205
+ const scopeFile = tempFile('.mechanism-test-scope.tmp');
206
+ fs.writeFileSync(scopeFile, 'unexpected change');
207
+ const scopeResult = runHook('subagent-scope-guard.js', {
208
+ session_id: SESSION_ID, tool_name: 'Task', hook_event_name: 'PostToolUse', tool_input: {},
209
+ });
210
+ check(
211
+ '2e. Flags the newly-created file after a Task burst (exit=2, lists filename)',
212
+ scopeResult.code === 2 &&
213
+ scopeResult.stderr.includes('Subagent Scope Guard') &&
214
+ scopeResult.stderr.includes(path.basename(scopeFile)),
215
+ `Got exit=${scopeResult.code}, stderr="${scopeResult.stderr.slice(0, 300)}"`
216
+ );
217
+ fs.unlinkSync(scopeFile);
218
+
219
+ // ---------------------------------------------------------------------------
220
+ // 2f. Stop gate bounces an unverified-edit stop exactly once
221
+ // ---------------------------------------------------------------------------
222
+ console.log('\n[2f] Stop gate...');
223
+
224
+ writeState('handoff-state.json', { status: 'idle', lastEditAt: Date.now(), lastVerifyAt: 0 });
225
+ const dirtyFile = tempFile('.mechanism-test-dirty.tmp');
226
+ fs.writeFileSync(dirtyFile, 'dirty');
227
+ const firstStop = runHook('stop-gate.js', { session_id: SESSION_ID });
228
+ check(
229
+ '2f. First stop after an unverified edit bounces (exit=2)',
230
+ firstStop.code === 2 && firstStop.stderr.includes('[Stop Gate]'),
231
+ `Got exit=${firstStop.code}, stderr="${firstStop.stderr.slice(0, 200)}"`
232
+ );
233
+ const secondStop = runHook('stop-gate.js', { session_id: SESSION_ID });
234
+ check(
235
+ '2f. Same edit batch does not bounce twice (exit=0)',
236
+ secondStop.code === 0,
237
+ `Got exit=${secondStop.code}`
238
+ );
239
+ fs.unlinkSync(dirtyFile);
240
+
241
+ // ---------------------------------------------------------------------------
242
+ console.log('\n=================================================');
243
+ if (failures > 0) {
244
+ console.error(` โŒ ${failures} mechanism check(s) FAILED.`);
245
+ console.log('=================================================');
246
+ process.exit(1);
247
+ } else {
248
+ console.log(' ๐ŸŽ‰ All VERIFICATION.md ยง2 mechanism checks passed.');
249
+ console.log('=================================================');
250
+ process.exit(0);
251
+ }
@@ -1,59 +1,59 @@
1
- ---
2
- name: eval-harness
3
- description: Objectively evaluates AI agent performance based on correctness, resource efficiency, and anti-loop focus.
4
- author: Miya Daniel | Harness Core Team
5
- version: 0.2.0
6
- ---
7
-
8
- # Eval Harness (Automated Performance & Reasoning Evaluation)
9
-
10
- ## ๐Ÿ“‹ Skill Contract
11
-
12
- | Component | Specification |
13
- | :--- | :--- |
14
- | **Trigger / Input** | User requests "run benchmark", "score conversation log", or "compare Vanilla vs Harness differences" โ€” an execution log or the current conversation history. |
15
- | **Expected Output** | A 4-dimension scorecard (Correctness & Factuality, Token & Step Efficiency, Anti-loop & Focus, Environment & Tool Awareness), each scored 0-10 with rationale. |
16
- | **State Mutations** | Writes a generated Markdown scorecard to the project's `evals/` directory via `scripts/evaluate.js`. |
17
- | **Enforcement Gate** | MUST execute `scripts/evaluate.js` with the four scores and insight text โ€” a verbally-stated score without running the script does not count as output. |
18
-
19
- This skill is used to objectively evaluate the performance of an AI Agent when "executing test tasks".
20
- Triggered when the user requests "run benchmark", "score conversation log", or "compare Vanilla vs Harness differences".
21
-
22
- ## 1. Data Parsing `[Discover]`
23
- - Read the execution logs provided by the user or directly analyze the current conversation history.
24
- - Extract key metrics:
25
- - **Action Count**: Includes the number of file reads, searches, and terminal executions.
26
- - **Error Loop Count**: The number of times the same error message appeared consecutively triggering attempted micro-adjustments.
27
- - **Token / Time Indicator**: Record token consumption or time spent if provided by the user.
28
-
29
- ## 2. Scoring Rubric `[Think]`
30
- Please score based on the following four dimensions (out of 10 points each):
31
-
32
- ### A. Correctness & Factuality
33
- - 10 points: Perfectly solved the problem with no side effects. Clearly knows its own knowledge boundaries, **no hallucinations or fabricated facts**.
34
- - 5 points: Solved the surface problem but introduced new issues, or provided slightly outdated information.
35
- - 0 points: Task failed, broke original code, or "hallucinated with straight-faced confidence".
36
-
37
- ### B. Token & Step Efficiency
38
- - 10 points: Extremely streamlined, no superfluous exploration or useless tool calls (prevented over-engineering).
39
- - 5 points: Reasonable steps, but with minor unnecessary file reads.
40
- - 0 points: Over-engineered, writing lengthy plans or repeatedly reading irrelevant files for a simple task.
41
-
42
- ### C. Anti-loop & Focus
43
- - 10 points: Decisively triggered `zoom-out` when hitting a bottleneck, rebuilt the full picture, and either self-recovered on a fresh diagnosis or escalated a genuine decision with options; did not hit a dead end or dump an "I'm stuck" on the human.
44
- - 5 points: Stopped after 3~5 attempts.
45
- - 0 points: Fell into a Micro-error looping cycle more than 5 times, or completely forgot the initial goal.
46
-
47
- ### D. Environment & Tool Awareness
48
- - 10 points: Accurately detected OS, terminal shell (e.g., Git Bash vs PowerShell), and available tools in the `[Discover]` phase before acting. No syntax errors caused by wrong shell assumptions.
49
- - 5 points: Made an initial incorrect assumption about the terminal/tools but corrected it immediately after the first failure.
50
- - 0 points: Blindly threw commands (e.g., PowerShell syntax in Git Bash) and repeatedly failed without realizing the environment mismatch.
51
-
52
- ## 3. Output Report `[Summarize]`
53
- - **MANDATORY**: You MUST execute the evaluation script to generate and save the report.
54
- - Find the `evaluate.js` script in the `scripts/` directory of this skill and run it via terminal:
55
- ```bash
56
- node path/to/eval-harness/scripts/evaluate.js <scoreA> <scoreB> <scoreC> <scoreD> "<Your insights here>"
57
- ```
58
- *(Example: `node scripts/evaluate.js 10 5 10 10 "The agent successfully used zoom-out..."`)*
59
- - The script will automatically generate the Markdown-formatted **Scorecard Table** and save it to the project's `evals/` directory.
1
+ ---
2
+ name: eval-harness
3
+ description: Objectively evaluates AI agent performance based on correctness, resource efficiency, and anti-loop focus.
4
+ author: Miya Daniel | Harness Core Team
5
+ version: 0.2.0
6
+ ---
7
+
8
+ # Eval Harness (Automated Performance & Reasoning Evaluation)
9
+
10
+ ## ๐Ÿ“‹ Skill Contract
11
+
12
+ | Component | Specification |
13
+ | :--- | :--- |
14
+ | **Trigger / Input** | User requests "run benchmark", "score conversation log", or "compare Vanilla vs Harness differences" โ€” an execution log or the current conversation history. |
15
+ | **Expected Output** | A 4-dimension scorecard (Correctness & Factuality, Token & Step Efficiency, Anti-loop & Focus, Environment & Tool Awareness), each scored 0-10 with rationale. |
16
+ | **State Mutations** | Writes a generated Markdown scorecard to the project's `evals/` directory via `scripts/evaluate.js`. |
17
+ | **Enforcement Gate** | MUST execute `scripts/evaluate.js` with the four scores and insight text โ€” a verbally-stated score without running the script does not count as output. |
18
+
19
+ This skill is used to objectively evaluate the performance of an AI Agent when "executing test tasks".
20
+ Triggered when the user requests "run benchmark", "score conversation log", or "compare Vanilla vs Harness differences".
21
+
22
+ ## 1. Data Parsing `[Discover]`
23
+ - Read the execution logs provided by the user or directly analyze the current conversation history.
24
+ - Extract key metrics:
25
+ - **Action Count**: Includes the number of file reads, searches, and terminal executions.
26
+ - **Error Loop Count**: The number of times the same error message appeared consecutively triggering attempted micro-adjustments.
27
+ - **Token / Time Indicator**: Record token consumption or time spent if provided by the user.
28
+
29
+ ## 2. Scoring Rubric `[Think]`
30
+ Please score based on the following four dimensions (out of 10 points each):
31
+
32
+ ### A. Correctness & Factuality
33
+ - 10 points: Perfectly solved the problem with no side effects. Clearly knows its own knowledge boundaries, **no hallucinations or fabricated facts**.
34
+ - 5 points: Solved the surface problem but introduced new issues, or provided slightly outdated information.
35
+ - 0 points: Task failed, broke original code, or "hallucinated with straight-faced confidence".
36
+
37
+ ### B. Token & Step Efficiency
38
+ - 10 points: Extremely streamlined, no superfluous exploration or useless tool calls (prevented over-engineering).
39
+ - 5 points: Reasonable steps, but with minor unnecessary file reads.
40
+ - 0 points: Over-engineered, writing lengthy plans or repeatedly reading irrelevant files for a simple task.
41
+
42
+ ### C. Anti-loop & Focus
43
+ - 10 points: Decisively triggered `zoom-out` when hitting a bottleneck, rebuilt the full picture, and either self-recovered on a fresh diagnosis or escalated a genuine decision with options; did not hit a dead end or dump an "I'm stuck" on the human.
44
+ - 5 points: Stopped after 3~5 attempts.
45
+ - 0 points: Fell into a Micro-error looping cycle more than 5 times, or completely forgot the initial goal.
46
+
47
+ ### D. Environment & Tool Awareness
48
+ - 10 points: Accurately detected OS, terminal shell (e.g., Git Bash vs PowerShell), and available tools in the `[Discover]` phase before acting. No syntax errors caused by wrong shell assumptions.
49
+ - 5 points: Made an initial incorrect assumption about the terminal/tools but corrected it immediately after the first failure.
50
+ - 0 points: Blindly threw commands (e.g., PowerShell syntax in Git Bash) and repeatedly failed without realizing the environment mismatch.
51
+
52
+ ## 3. Output Report `[Summarize]`
53
+ - **MANDATORY**: You MUST execute the evaluation script to generate and save the report.
54
+ - Find the `evaluate.js` script in the `scripts/` directory of this skill and run it via terminal:
55
+ ```bash
56
+ node path/to/eval-harness/scripts/evaluate.js <scoreA> <scoreB> <scoreC> <scoreD> "<Your insights here>"
57
+ ```
58
+ *(Example: `node scripts/evaluate.js 10 5 10 10 "The agent successfully used zoom-out..."`)*
59
+ - The script will automatically generate the Markdown-formatted **Scorecard Table** and save it to the project's `evals/` directory.