harness-everything 0.16.2 → 0.16.4

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 (32) 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/ci/consistency-check.js +100 -0
  5. package/ci/mechanism-33-issues-205-207.test.js +59 -0
  6. package/commitlint.config.js +2 -2
  7. package/docker-verify.sh +59 -24
  8. package/docs/architecture.md +1 -1
  9. package/docs/mechanism-first-skill-mesh.md +1 -1
  10. package/docs/workflows/zoom-out.md +6 -6
  11. package/fable-mode/CONTRACT-FORMAT.md +2 -1
  12. package/fable-mode/SKILL.md +1 -1
  13. package/fable-mode/agents/fable-orchestrator.md +6 -5
  14. package/fable-mode/execution-guardrails/SKILL.md +1 -1
  15. package/fable-mode/fable-haiku/SKILL.md +1 -1
  16. package/fable-mode/fable-opus/SKILL.md +1 -1
  17. package/fable-mode/fable-sonnet/SKILL.md +1 -1
  18. package/harness-everything/SKILL.md +1 -1
  19. package/harness-everything/references/router-workflow-plan.md +1 -1
  20. package/opencode-plugin/plugin.json +1 -1
  21. package/package.json +1 -1
  22. package/plugins/harness-everything/.codex-plugin/plugin.json +1 -1
  23. package/plugins/harness-everything/plugin.json +1 -1
  24. package/plugins/harness-everything/skills/fable-mode/CONTRACT-FORMAT.md +2 -1
  25. package/plugins/harness-everything/skills/fable-mode/SKILL.md +1 -1
  26. package/plugins/harness-everything/skills/fable-mode/agents/fable-orchestrator.md +6 -5
  27. package/plugins/harness-everything/skills/fable-mode/execution-guardrails/SKILL.md +1 -1
  28. package/plugins/harness-everything/skills/fable-mode/fable-haiku/SKILL.md +1 -1
  29. package/plugins/harness-everything/skills/fable-mode/fable-opus/SKILL.md +1 -1
  30. package/plugins/harness-everything/skills/fable-mode/fable-sonnet/SKILL.md +1 -1
  31. package/plugins/harness-everything/skills/harness-everything/SKILL.md +1 -1
  32. package/plugins/harness-everything/skills/harness-everything/references/router-workflow-plan.md +1 -1
@@ -10,7 +10,7 @@
10
10
  "name": "harness-everything",
11
11
  "source": "./",
12
12
  "description": "Harness OS: an orchestrated agent operating system — tier routing, circuit breaker guardrails, verification gates, WAL session memory, and self-evolving workspace rules.",
13
- "version": "0.16.2",
13
+ "version": "0.16.4",
14
14
  "author": {
15
15
  "name": "Miya Daniel"
16
16
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "harness-everything",
3
3
  "description": "Harness OS: an orchestrated agent operating system — tier routing, circuit breaker guardrails, verification gates, WAL session memory, and self-evolving workspace rules.",
4
- "version": "0.16.2",
4
+ "version": "0.16.4",
5
5
  "author": {
6
6
  "name": "Miya Daniel"
7
7
  },
package/CHANGELOG.md CHANGED
@@ -2,6 +2,18 @@
2
2
 
3
3
  All notable changes to this project are documented in this file.
4
4
 
5
+ ## [0.16.4](https://github.com/dyphn1/Harness-everything/compare/v0.16.3...v0.16.4) (2026-09-20)
6
+
7
+ ### Bug Fixes
8
+
9
+ * **repo:** close issues 205-207 ([423ff63](https://github.com/dyphn1/Harness-everything/commit/423ff638f08cdaa14d4ab0856bfe2d2bc6b050db)), closes [#205](https://github.com/dyphn1/Harness-everything/issues/205) [#206](https://github.com/dyphn1/Harness-everything/issues/206) [#205](https://github.com/dyphn1/Harness-everything/issues/205) [#206](https://github.com/dyphn1/Harness-everything/issues/206) [#207](https://github.com/dyphn1/Harness-everything/issues/207)
10
+
11
+ ## [0.16.3](https://github.com/dyphn1/Harness-everything/compare/v0.16.2...v0.16.3) (2026-09-20)
12
+
13
+ ### Bug Fixes
14
+
15
+ * **docker:** Verify current re-trip contract in docker-verify.sh ([#200](https://github.com/dyphn1/Harness-everything/issues/200)) ([610ce32](https://github.com/dyphn1/Harness-everything/commit/610ce32733a74dd4a16f68d171346ea8b10f8d62)), closes [#190](https://github.com/dyphn1/Harness-everything/issues/190) [#42](https://github.com/dyphn1/Harness-everything/issues/42)
16
+
5
17
  ## [0.16.2](https://github.com/dyphn1/Harness-everything/compare/v0.16.1...v0.16.2) (2026-09-20)
6
18
 
7
19
  ### Bug Fixes
@@ -164,6 +164,106 @@ for (const [rel, pattern] of retiredClaims) {
164
164
  check(`${rel}: retired enforcement claim absent (${pattern})`, !pattern.test(text), 'stale pre-#190 contract wording');
165
165
  }
166
166
 
167
+ // The per-file entries above only freeze the files a past fix touched, so the
168
+ // same retired wording survived elsewhere (#204: docs/workflows/zoom-out.md,
169
+ // docker-verify.sh). Scan the whole agent-facing surface instead: docs, routed
170
+ // skills, shared references, the OpenCode README, root shell/container entry
171
+ // points, and the packaged plugin copies that ship to other hosts.
172
+ const RETIRED_CLAIM_DIRS = [
173
+ 'docs',
174
+ 'zoom-out',
175
+ 'fable-mode',
176
+ 'harness-everything/references',
177
+ 'plugins/harness-everything',
178
+ ];
179
+ const RETIRED_CLAIM_EXTENSIONS = new Set(['.md', '.sh', '.js', '.mjs']);
180
+
181
+ // Files that legitimately keep the retired wording: retained pre-#190
182
+ // live-host evidence, release history, capability docs whose hard-lock lines
183
+ // are explicitly labelled historical/reported-only, code that strips the
184
+ // retired state field, and the CI guards that assert its absence.
185
+ const RETIRED_CLAIM_ALLOWLIST = [
186
+ /^benchmarks\/results\/live-host\/opencode-2026-09-16\//,
187
+ /^CHANGELOG\.md$/,
188
+ /^docs\/platform-capabilities\.md$/,
189
+ /^opencode-plugin\/index\.mjs$/,
190
+ /^ci\//,
191
+ /^behavioral-evals\/[^/]+\.js$/,
192
+ ];
193
+
194
+ // A line that denies the retired behavior or dates it ("no permanent hard
195
+ // lock", "historical hard-lock evidence", "predates #190") is the correct
196
+ // wording, not drift. Only the broad hard-lock family needs this escape; the
197
+ // assertive patterns below are wrong in any context, so they never get it.
198
+ const HISTORICAL_CONTEXT =
199
+ /pre-#190|\b(?:no|not|never|without|remove[sd]?|retired|historical|predates|former(?:ly)?|legacy|post-reset|no longer)\b|rather than|instead of/i;
200
+
201
+ const RETIRED_CLAIM_SCAN = [
202
+ { label: 'hard-lock escalation', pattern: /hard[\s-]?lock/i, historicalAllowed: true },
203
+ { label: 'reset gated on a second cycle', pattern: /only after the (?:second|repeated) cycle/i },
204
+ { label: 'cycle-escalation reset branch', pattern: /\|\s*(?:second|repeated|repeat) cycle\s*\|\s*reset/i },
205
+ { label: 'machine-blocked disposition', pattern: /machine[\s-]blocked/i },
206
+ { label: 'replan budget', pattern: /replan[\s-]budget/i },
207
+ { label: 'runtime worker leases', pattern: /worker lease/i },
208
+ { label: 'retired loop-budget invariant', pattern: /\bloop-budget\b/i },
209
+ { label: 'explicit iteration budget', pattern: /explicit iteration budget/i },
210
+ ];
211
+
212
+ function collectRetiredClaimTargets() {
213
+ const targets = new Set();
214
+ const walk = (dir) => {
215
+ let entries;
216
+ try { entries = fs.readdirSync(dir, { withFileTypes: true }); } catch { return; }
217
+ for (const entry of entries) {
218
+ const p = path.join(dir, entry.name);
219
+ if (entry.isDirectory()) {
220
+ if (!entry.name.startsWith('.') && entry.name !== 'node_modules') walk(p);
221
+ } else if (RETIRED_CLAIM_EXTENSIONS.has(path.extname(entry.name))) {
222
+ targets.add(p);
223
+ }
224
+ }
225
+ };
226
+ for (const dir of RETIRED_CLAIM_DIRS) walk(path.join(ROOT, dir));
227
+ for (const entry of fs.readdirSync(ROOT, { withFileTypes: true })) {
228
+ if (entry.isFile() && (entry.name.endsWith('.sh') || entry.name === 'Dockerfile')) {
229
+ targets.add(path.join(ROOT, entry.name));
230
+ }
231
+ }
232
+ const behavioralDir = path.join(ROOT, 'behavioral-evals');
233
+ if (fs.existsSync(behavioralDir)) {
234
+ for (const entry of fs.readdirSync(behavioralDir, { withFileTypes: true })) {
235
+ if (entry.isFile() && entry.name.endsWith('.md')) targets.add(path.join(behavioralDir, entry.name));
236
+ }
237
+ }
238
+ const opencodeReadme = path.join(ROOT, 'opencode-plugin', 'README.md');
239
+ if (fs.existsSync(opencodeReadme)) targets.add(opencodeReadme);
240
+ return [...targets].sort();
241
+ }
242
+
243
+ const retiredClaimTargets = collectRetiredClaimTargets();
244
+ const retiredClaimHits = new Map(RETIRED_CLAIM_SCAN.map((rule) => [rule.label, []]));
245
+ for (const file of retiredClaimTargets) {
246
+ const rel = path.relative(ROOT, file).split(path.sep).join('/');
247
+ if (RETIRED_CLAIM_ALLOWLIST.some((allowed) => allowed.test(rel))) continue;
248
+ const lines = fs.readFileSync(file, 'utf8').split(/\r?\n/);
249
+ lines.forEach((line, index) => {
250
+ for (const rule of RETIRED_CLAIM_SCAN) {
251
+ if (!rule.pattern.test(line)) continue;
252
+ if (rule.historicalAllowed && HISTORICAL_CONTEXT.test(line)) continue;
253
+ retiredClaimHits.get(rule.label).push(`${rel}:${index + 1}`);
254
+ }
255
+ });
256
+ }
257
+ for (const rule of RETIRED_CLAIM_SCAN) {
258
+ const hits = retiredClaimHits.get(rule.label);
259
+ check(
260
+ `retired-claim scan: ${rule.label} absent across the agent-facing surface`,
261
+ hits.length === 0,
262
+ `stale pre-#190 contract wording at ${hits.join(', ')}`
263
+ );
264
+ }
265
+ console.log(`Scanned ${retiredClaimTargets.length} file(s) for retired advisory-contract claims.`);
266
+
167
267
  // --- 3+4. Distribution manifests -----------------------------------------
168
268
  const pkg = JSON.parse(fs.readFileSync(path.join(ROOT, 'package.json'), 'utf8'));
169
269
  const pluginJsonPath = path.join(ROOT, '.claude-plugin', 'plugin.json');
@@ -0,0 +1,59 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const fs = require('fs');
5
+ const os = require('os');
6
+ const path = require('path');
7
+ const { spawnSync } = require('child_process');
8
+
9
+ const ROOT = path.resolve(__dirname, '..');
10
+ let failed = 0;
11
+
12
+ function check(condition, message) {
13
+ if (condition) {
14
+ console.log(`PASS ${message}`);
15
+ } else {
16
+ failed += 1;
17
+ console.error(`FAIL ${message}`);
18
+ }
19
+ }
20
+
21
+ const dockerVerify = fs.readFileSync(path.join(ROOT, 'docker-verify.sh'), 'utf8');
22
+ const legacyStatePath = '.claude/harness-everything/state/sessions/default';
23
+ check(/STATE_DIR=\$\(node -e[\s\S]*getSessionDir\(null, 'default'\)/.test(dockerVerify),
24
+ '#205 docker verifier resolves one canonical session state directory');
25
+ check(!dockerVerify.includes(legacyStatePath),
26
+ '#205 docker verifier does not seed or read the legacy repo-relative state directory');
27
+ check((dockerVerify.match(/\$STATE_DIR\//g) || []).length >= 10,
28
+ '#205 docker verifier routes all state checks through STATE_DIR');
29
+
30
+ const architecture = fs.readFileSync(path.join(ROOT, 'docs/architecture.md'), 'utf8');
31
+ check(architecture.includes('advisory loop-awareness reminders'),
32
+ '#206 architecture names loop-awareness as advisory');
33
+ check(!/\bloop budgets\b/.test(architecture),
34
+ '#206 architecture does not describe retired loop budgets as enforcement');
35
+
36
+ const commitlintConfig = require(path.join(ROOT, 'commitlint.config.js'));
37
+ check(JSON.stringify(commitlintConfig.rules['subject-case']) === JSON.stringify([2, 'always', 'lower-case']),
38
+ '#207 commitlint aligns subject-case with repository Conventional Commit history');
39
+
40
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'harness-issue-207-'));
41
+ const messageFile = path.join(tempDir, 'commit-message.txt');
42
+ fs.writeFileSync(messageFile, 'fix(runtime): align post-190 advisory contracts\n', 'utf8');
43
+ const commitlintPackage = require.resolve('@commitlint/cli/package.json');
44
+ const commitlintMeta = JSON.parse(fs.readFileSync(commitlintPackage, 'utf8'));
45
+ const commitlintBin = typeof commitlintMeta.bin === 'string'
46
+ ? commitlintMeta.bin
47
+ : commitlintMeta.bin.commitlint;
48
+ const commitlintCli = path.resolve(path.dirname(commitlintPackage), commitlintBin);
49
+ const result = spawnSync(process.execPath, [commitlintCli, '--edit', messageFile], {
50
+ cwd: ROOT,
51
+ encoding: 'utf8',
52
+ });
53
+ check(result.status === 0,
54
+ '#207 representative lowercase repository subject passes commitlint');
55
+
56
+ fs.rmSync(tempDir, { recursive: true, force: true });
57
+
58
+ console.log(`\n${failed === 0 ? 'PASS' : 'FAIL'}: issues #205-#207 regression mechanism (${failed} failure${failed === 1 ? '' : 's'})`);
59
+ process.exit(failed === 0 ? 0 : 1);
@@ -18,8 +18,8 @@ module.exports = {
18
18
  'build'
19
19
  ]
20
20
  ],
21
- 'subject-case': [2, 'always', 'sentence-case'],
21
+ 'subject-case': [2, 'always', 'lower-case'],
22
22
  'subject-empty': [2, 'never'],
23
23
  'header-max-length': [2, 'always', 100]
24
24
  }
25
- };
25
+ };
package/docker-verify.sh CHANGED
@@ -26,13 +26,12 @@ npm test
26
26
  echo -e "\n[Step 3] Running Mechanism Checks..."
27
27
 
28
28
  # 3a. Rule of 3 Circuit Breaker actually blocks
29
- # Runtime state lives under .claude/harness-everything/state/sessions/<session_id>/;
30
- # invocations with no session_id (like these bare/manual calls) fall into a
31
- # fixed sessions/default/ bucket.
29
+ # Runtime state is resolved once through the same workspace-keyed helper used by
30
+ # the hooks. Invocations with no session_id use the fixed default session.
31
+ STATE_DIR=$(node -e "process.stdout.write(require('./hooks/scripts/lib/harness-state').getSessionDir(null, 'default'))")
32
32
  echo -e "\n---> Running 3a: Rule of 3 Circuit Breaker"
33
- mkdir -p .claude/harness-everything/state/sessions/default
34
- rm -f .claude/harness-everything/state/sessions/default/zoom-out-report.md
35
- echo '{"count":3,"lastHash":"verify-test","zoomOutResolved":false}' > .claude/harness-everything/state/sessions/default/rule-of-3-state.json
33
+ rm -f "$STATE_DIR/zoom-out-report.md"
34
+ echo '{"count":3,"lastHash":"verify-test","zoomOutResolved":false}' > "$STATE_DIR/rule-of-3-state.json"
36
35
 
37
36
  # We expect this to exit with 2 and print CRITICAL trigger message
38
37
  set +e
@@ -68,8 +67,8 @@ echo "✅ PASS: Rule of 3 reset check passed."
68
67
 
69
68
  # 3a-bis. Zoom-out reflection report releases the breaker (self-recovery path)
70
69
  echo -e "\n---> Running 3a-bis: Zoom-out report releases the breaker"
71
- echo '{"count":3,"lastHash":"verify-test","zoomOutResolved":false,"lastFailureAt":0,"zoomOutCycles":0}' > .claude/harness-everything/state/sessions/default/rule-of-3-state.json
72
- printf '## Goal\nx\n## Failed Attempts\nx\n## Verified Facts\nx\n## Diagnosis\nx\n## Decision\nRESUME: new approach\n' > .claude/harness-everything/state/sessions/default/zoom-out-report.md
70
+ echo '{"count":3,"lastHash":"verify-test","zoomOutResolved":false,"lastFailureAt":0,"zoomOutCycles":0}' > "$STATE_DIR/rule-of-3-state.json"
71
+ printf '## Goal\nx\n## Failed Attempts\nx\n## Verified Facts\nx\n## Diagnosis\nx\n## Decision\nRESUME: new approach\n' > "$STATE_DIR/zoom-out-report.md"
73
72
 
74
73
  set +e
75
74
  node hooks/scripts/rule-of-3.js
@@ -79,31 +78,67 @@ if [ "$EXIT_CODE" -ne 0 ]; then
79
78
  echo "❌ FAIL: Valid reflection report did not release the breaker (expected 0, got $EXIT_CODE)"
80
79
  exit 1
81
80
  fi
82
- if ! node -e "const s=require('./.claude/harness-everything/state/sessions/default/rule-of-3-state.json'); process.exit(s.count===0 && s.zoomOutResolved===true && s.zoomOutCycles===1 ? 0 : 1)"; then
81
+ if ! node -e "const s=require(process.argv[1]); process.exit(s.count===0 && s.zoomOutResolved===true && s.zoomOutCycles===1 ? 0 : 1)" "$STATE_DIR/rule-of-3-state.json"; then
83
82
  echo "❌ FAIL: Breaker state not updated after report release"
84
- cat .claude/harness-everything/state/sessions/default/rule-of-3-state.json
83
+ cat "$STATE_DIR/rule-of-3-state.json"
85
84
  exit 1
86
85
  fi
87
86
  echo "✅ PASS: Valid reflection report released the breaker (self-recovery)."
88
87
 
89
- # Second trip on the same signature must hard-lock even though a report exists
90
- # (the report is stale relative to lastFailureAt, and the cycle budget is spent).
91
- node -e "require('fs').writeFileSync('.claude/harness-everything/state/sessions/default/rule-of-3-state.json', JSON.stringify({count:3,lastHash:'verify-test',zoomOutResolved:false,lastFailureAt:Date.now()+60000,zoomOutCycles:1}))"
88
+ # 3a-ter. Re-trip: three more failures on the same signature after a released
89
+ # cycle ask for ANOTHER zoom-out. #190 retired the second-stage escalation, so
90
+ # the contract is exit 2 plus the reflection-required message the hook actually
91
+ # prints - never a permanent lock (ci/mechanism-2a-rule-of-3.test.js:58-64).
92
+ echo -e "\n---> Running 3a-ter: Re-trip requests another zoom-out"
93
+ # Seed through the hooks' own resolver in the already resolved workspace-keyed
94
+ # state root.
95
+ RETRIP_AT=$(node -e "process.stdout.write(String(Date.now()))")
96
+ node -e "require('fs').writeFileSync(process.argv[1], JSON.stringify({count:3,lastHash:'verify-test',zoomOutResolved:false,lastFailureAt:Number(process.argv[2]),zoomOutCycles:1}))" "$STATE_DIR/rule-of-3-state.json" "$RETRIP_AT"
92
97
  set +e
93
98
  node hooks/scripts/rule-of-3.js 2>rule-of-3-err.log
94
99
  EXIT_CODE=$?
95
100
  set -e
96
101
  if [ "$EXIT_CODE" -ne 2 ]; then
97
- echo "❌ FAIL: Second trip did not hard-lock (expected 2, got $EXIT_CODE)"
102
+ echo "❌ FAIL: Re-trip did not request another zoom-out (expected 2, got $EXIT_CODE)"
98
103
  cat rule-of-3-err.log
99
104
  exit 1
100
105
  fi
101
- if ! grep -q "hard lock" rule-of-3-err.log; then
102
- echo "❌ FAIL: Second-trip output did not contain hard-lock escalation message"
106
+ if ! grep -q "RULE OF 3 CIRCUIT BREAKER TRIGGERED" rule-of-3-err.log; then
107
+ echo "❌ FAIL: Re-trip output did not contain the circuit-breaker trigger message"
103
108
  cat rule-of-3-err.log
104
109
  exit 1
105
110
  fi
106
- echo "✅ PASS: Second trip on the same signature hard-locked for human decision."
111
+ if ! grep -q "ACTION REQUIRED (reflect first)" rule-of-3-err.log; then
112
+ echo "❌ FAIL: Re-trip output did not demand reflection"
113
+ cat rule-of-3-err.log
114
+ exit 1
115
+ fi
116
+ # Negative guard: the retired escalation wording must never come back (#190).
117
+ if grep -qi "hard lock" rule-of-3-err.log; then # this must never match
118
+ echo "❌ FAIL: Re-trip printed the retired hard-lock escalation, which no longer exists"
119
+ cat rule-of-3-err.log
120
+ exit 1
121
+ fi
122
+ echo "✅ PASS: Re-trip asked for another zoom-out, with no retired escalation wording."
123
+
124
+ # A fresh report, written after the re-trip failure, releases the breaker again.
125
+ printf '## Goal\nx\n## Failed Attempts\nx\n## Verified Facts\nx\n## Diagnosis\nx\n## Decision\nRESUME: second untried approach\n' > "$STATE_DIR/zoom-out-report.md"
126
+ set +e
127
+ node hooks/scripts/rule-of-3.js
128
+ EXIT_CODE=$?
129
+ set -e
130
+ if [ "$EXIT_CODE" -ne 0 ]; then
131
+ echo "❌ FAIL: Fresh reflection report did not release the re-tripped breaker (expected 0, got $EXIT_CODE)"
132
+ exit 1
133
+ fi
134
+ if ! node -e "const s=JSON.parse(require('fs').readFileSync(process.argv[1],'utf8')); process.exit(s.count===0 && s.zoomOutResolved===true && s.zoomOutCycles===2 ? 0 : 1)" "$STATE_DIR/rule-of-3-state.json"; then
135
+ echo "❌ FAIL: Breaker state not updated after the second report release"
136
+ cat "$STATE_DIR/rule-of-3-state.json"
137
+ exit 1
138
+ fi
139
+ echo "✅ PASS: A fresh report released the re-tripped breaker (advisory re-trip, not an escalation)."
140
+
141
+ # harness:reset stays an optional manual clear, not a required escalation step.
107
142
  npm run harness:reset
108
143
 
109
144
 
@@ -134,17 +169,17 @@ echo "✅ PASS: Boundary Guard blocked large read successfully."
134
169
 
135
170
  # 3c. State persistence (WAL) records failure and handles clear
136
171
  echo -e "\n---> Running 3c: State persistence (WAL)"
137
- rm -f .claude/harness-everything/state/sessions/default/handoff-state.json
172
+ rm -f "$STATE_DIR/handoff-state.json"
138
173
 
139
174
  # Record failure
140
175
  echo '{"tool_name":"Bash","tool_response":{"stdout":"","stderr":"npm ERR! verify-test failure"}}' | node hooks/scripts/state-persist.js
141
176
 
142
- if [ ! -f ".claude/harness-everything/state/sessions/default/handoff-state.json" ]; then
177
+ if [ ! -f "$STATE_DIR/handoff-state.json" ]; then
143
178
  echo "❌ FAIL: handoff-state.json was not created"
144
179
  exit 1
145
180
  fi
146
181
 
147
- STATUS=$(node -e "console.log(JSON.parse(require('fs').readFileSync('.claude/harness-everything/state/sessions/default/handoff-state.json','utf8')).status)")
182
+ STATUS=$(node -e "console.log(JSON.parse(require('fs').readFileSync(process.argv[1],'utf8')).status)" "$STATE_DIR/handoff-state.json")
148
183
  if [ "$STATUS" != "failed" ]; then
149
184
  echo "❌ FAIL: Expected status to be 'failed', got '$STATUS'"
150
185
  exit 1
@@ -215,8 +250,8 @@ echo "✅ PASS: Subagent scope guard successfully blocked out-of-scope modificat
215
250
 
216
251
  # 3f. Stop gate bounces an unverified-edit stop exactly once
217
252
  echo -e "\n---> Running 3f: Stop Gate"
218
- rm -f .claude/harness-everything/state/sessions/default/stop-gate-state.json
219
- node -e "require('fs').mkdirSync('.claude/harness-everything/state/sessions/default',{recursive:true}); require('fs').writeFileSync('.claude/harness-everything/state/sessions/default/handoff-state.json', JSON.stringify({status:'idle',lastEditAt:Date.now(),lastVerifyAt:0}))"
253
+ rm -f "$STATE_DIR/stop-gate-state.json"
254
+ node -e "require('fs').writeFileSync(process.argv[1], JSON.stringify({status:'idle',lastEditAt:Date.now(),lastVerifyAt:0}))" "$STATE_DIR/handoff-state.json"
220
255
  echo "dirty" > .verify-dirty.tmp
221
256
 
222
257
  set +e
@@ -246,7 +281,7 @@ if [ "$EXIT_CODE" -ne 0 ]; then
246
281
  fi
247
282
 
248
283
  # Loop guard: stop_hook_active always passes
249
- rm -f .claude/harness-everything/state/sessions/default/stop-gate-state.json
284
+ rm -f "$STATE_DIR/stop-gate-state.json"
250
285
  set +e
251
286
  echo '{"stop_hook_active":true}' | node hooks/scripts/stop-gate.js
252
287
  EXIT_CODE=$?
@@ -255,7 +290,7 @@ if [ "$EXIT_CODE" -ne 0 ]; then
255
290
  echo "❌ FAIL: Stop gate blocked despite stop_hook_active (expected 0, got $EXIT_CODE)"
256
291
  exit 1
257
292
  fi
258
- rm -f .verify-dirty.tmp .claude/harness-everything/state/sessions/default/handoff-state.json .claude/harness-everything/state/sessions/default/stop-gate-state.json
293
+ rm -f .verify-dirty.tmp "$STATE_DIR/handoff-state.json" "$STATE_DIR/stop-gate-state.json"
259
294
  echo "✅ PASS: Stop gate bounced once, then respected the batch and loop guards."
260
295
 
261
296
  # Clean up temporary test output logs
@@ -71,7 +71,7 @@ For selected Fable topologies on Claude:
71
71
  - `workflow-stop-gate.js` reports unresolved stage/verification evidence without rejecting Stop;
72
72
  - `workflow-disposition.js` records explicit lifecycle/audit decisions; numeric budgets are no longer authoritative control state.
73
73
 
74
- Other topologies use their own applicable mechanisms: loop budgets, regular verification stop-gates, action gates, and task-specific skills. Mechanism coverage is not assumed identical across hosts.
74
+ Other topologies use their own applicable mechanisms: advisory loop-awareness reminders, regular verification stop-gates, action gates, and task-specific skills. Mechanism coverage is not assumed identical across hosts.
75
75
 
76
76
  ### Scoped runtime advisories and capabilities
77
77
 
@@ -55,7 +55,7 @@ HARNESS_DECISION
55
55
  tier: 2
56
56
  strategy: iterative-single
57
57
  workflow_state: active
58
- required: route-before-execution, objective-verification, loop-budget
58
+ required: scope-lock, objective-verification, loop-awareness
59
59
  suggest: tdd, verification-loop
60
60
  suggestion_policy: evaluate-applicability
61
61
  escape_policy: workflow-uncovered-scope-only
@@ -4,7 +4,7 @@
4
4
 
5
5
  Source of truth: `zoom-out/SKILL.md`.
6
6
 
7
- Contract summary from SKILL.md — Trigger: three same-signature failures or an explicit loop/rethink request. Output: fact-checked report ending in `RESUME` or `ESCALATE`. State: writes the session `zoom-out-report.md`; reset may clear breaker state. Gate: `hooks/scripts/rule-of-3.js` plus a valid report; reset only after the second cycle. USE FOR: "you are stuck in a loop", "the same error keeps failing", "rethink your assumptions". DO NOT USE FOR: routine single-failure debugging, greenfield planning without failures.
7
+ Contract summary from SKILL.md — Trigger: three same-signature failures or an explicit loop/rethink request. Output: fact-checked report ending in `RESUME` or `ESCALATE`. State: writes the session `zoom-out-report.md`; reset may clear breaker state. Gate: `hooks/scripts/rule-of-3.js` plus a valid report; a later three-failure cycle requests another reflection. USE FOR: "you are stuck in a loop", "the same error keeps failing", "rethink your assumptions". DO NOT USE FOR: routine single-failure debugging, greenfield planning without failures.
8
8
 
9
9
  ## 1. Skill Behavior Workflow
10
10
 
@@ -16,9 +16,9 @@ graph TD
16
16
  Fill --> Decide{RESUME or ESCALATE?}
17
17
  Decide -->|untried path| Resume[RESUME On Untried Path]
18
18
  Decide -->|genuine user decision| Escalate[ESCALATE With Options]
19
- Resume --> Again{Repeated Breaker Cycle?}
20
- Again -->|second cycle| Reset[npm run harness reset]
21
- Reset --> Evolve[Record Insight With self-evolve]
19
+ Resume --> Again{Three More Matching Failures?}
20
+ Again -->|yes| Cycle[Another Zoom-Out Cycle]
21
+ Cycle --> Evolve[Record Insight With self-evolve]
22
22
  Again -->|no| Done([Report Complete])
23
23
  Escalate --> Done
24
24
  ```
@@ -47,7 +47,7 @@ graph TD
47
47
  Write --> Choice{Untried Path Exists?}
48
48
  Choice -->|yes| Resume2[RESUME On Untried Path]
49
49
  Choice -->|no| Esc2[ESCALATE With Options]
50
- Resume2 -->|repeated cycle| Reset2[npm run harness reset Then self-evolve]
50
+ Resume2 -->|three more matching failures| Cycle2[Another Zoom-Out Cycle Then self-evolve]
51
51
  ```
52
52
 
53
53
  Template: `zoom-out/templates/zoom-out-report.template.md`. Enforcement: `hooks/scripts/rule-of-3.js`. Deep dive: `zoom-out/references/circuit-breaker.md`.
@@ -58,5 +58,5 @@ Template: `zoom-out/templates/zoom-out-report.template.md`. Enforcement: `hooks/
58
58
  - [ ] Goal, files, configuration, and logs were rechecked with read-only tools before any resume
59
59
  - [ ] `templates/zoom-out-report.template.md` was filled and the session `zoom-out-report.md` ends in `RESUME` or `ESCALATE`
60
60
  - [ ] Resume targeted only an untried path; genuine user decisions were escalated with options
61
- - [ ] Reset via `npm run harness:reset` happened only after the second cycle, with the insight recorded via `self-evolve`
61
+ - [ ] A later three-failure cycle ran another zoom-out; `npm run harness:reset` was used only as an optional manual clear, with the insight recorded via `self-evolve`
62
62
  - [ ] Routine single-failure debugging and greenfield planning without failures were not routed here
@@ -2,7 +2,8 @@
2
2
 
3
3
  Issue #85 Phase 3 makes the stage map a machine-readable execution contract.
4
4
  The router still chooses only the execution topology. Fable owns the stage map,
5
- model selector, worker briefs, stage audit, replan budget, and cold verifier.
5
+ model selector, worker briefs, stage audit, advisory replan limits, and cold
6
+ verifier.
6
7
  Phase 4 adds an optional bounded ensemble modifier without creating a new base
7
8
  topology.
8
9
 
@@ -4,7 +4,7 @@ description: "Stage large, multi-source or multi-session tasks through a written
4
4
  license: Apache-2.0
5
5
  metadata:
6
6
  author: Miya Daniel
7
- version: 0.16.2
7
+ version: 0.16.3
8
8
  ---
9
9
 
10
10
  # Fable Mode (v3)
@@ -77,11 +77,12 @@ spawn workers.
77
77
 
78
78
  For `fable-parallel`, spawn only stages in the same validated execution batch;
79
79
  never invent an additional parallel edge. A stage depending on another stage is
80
- not in the same ready batch. Never exceed `workflowPlan.limits.maxWorkers`. The router plan is the numeric
81
- source of truth; `workflow-plan-consumer.js` chunks ready sets to that cap and
82
- runtime worker leases enforce it when the host exposes stable worker IDs. For
83
- other Fable strategies, serialize the returned batches unless a later validated
84
- plan says otherwise.
80
+ not in the same ready batch. Treat `workflowPlan.limits.maxWorkers` as a
81
+ planning cap you are expected to respect: it is advisory. `workflow-plan-consumer.js`
82
+ returns every dependency-ready stage without chunking to that cap, and nothing
83
+ leases or counts workers at runtime, so exceeding it is your own judgement call,
84
+ not a blocked action. For other Fable strategies, serialize the returned batches
85
+ unless a later validated plan says otherwise.
85
86
 
86
87
  **3. Verify with a check that can fail — external artifacts only.** Each stage
87
88
  defines a pass condition an external artifact satisfies: a test that runs, a file
@@ -7,7 +7,7 @@ description: >-
7
7
  license: Apache-2.0
8
8
  metadata:
9
9
  author: Miya Daniel
10
- version: 0.16.2
10
+ version: 0.16.3
11
11
  ---
12
12
 
13
13
  # Execution Guardrails
@@ -4,7 +4,7 @@ description: "Run staged fable work on Haiku for bulk mechanical tasks with expl
4
4
  license: Apache-2.0
5
5
  metadata:
6
6
  author: Miya Daniel
7
- version: 0.16.2
7
+ version: 0.16.3
8
8
  ---
9
9
 
10
10
  # Fable Mode — Haiku
@@ -4,7 +4,7 @@ description: "Run staged fable orchestration on Opus for cross-stage synthesis,
4
4
  license: Apache-2.0
5
5
  metadata:
6
6
  author: Miya Daniel
7
- version: 0.16.2
7
+ version: 0.16.3
8
8
  ---
9
9
 
10
10
  # Fable Mode — Opus
@@ -4,7 +4,7 @@ description: "Run staged fable work on Sonnet for non-trivial implementation, re
4
4
  license: Apache-2.0
5
5
  metadata:
6
6
  author: Miya Daniel
7
- version: 0.16.2
7
+ version: 0.16.3
8
8
  ---
9
9
 
10
10
  # Fable Mode — Sonnet
@@ -4,7 +4,7 @@ description: "Route software/project work through the Harness kernel: classify T
4
4
  license: Apache-2.0
5
5
  metadata:
6
6
  author: Miya Daniel
7
- version: 0.16.2
7
+ version: 0.16.3
8
8
  ---
9
9
 
10
10
  # Harness Everything
@@ -110,7 +110,7 @@ This does not choose a topology and does not itself enforce the gate. Phase 5 ow
110
110
 
111
111
  Examples:
112
112
 
113
- - `objective-verification` and `loop-budget` are mandatory for `iterative-single`;
113
+ - `loop-awareness` and `objective-verification` are mandatory for `iterative-single`, on top of the base `scope-lock`, `verify-before-claim`, and `replan-after-repeated-failure`;
114
114
  - `tdd` and `verification-loop` remain advisory skill suggestions;
115
115
  - `stage-contracts` and `cold-verification` are mandatory for Fable topologies;
116
116
  - `multi-agent-workspace` is suggested only when the selected topology actually requires durable workspace behavior.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "harness-enforcement",
3
3
  "description": "Repository inventory for the opencode enforcement plugin and its standalone helper",
4
- "version": "0.16.2",
4
+ "version": "0.16.4",
5
5
  "runtime": "index.mjs",
6
6
  "hooks": {
7
7
  "verify": "hooks/verify.js"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "harness-everything",
3
- "version": "0.16.2",
3
+ "version": "0.16.4",
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": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "harness-everything",
3
- "version": "0.16.2",
3
+ "version": "0.16.4",
4
4
  "description": "Invariant-first engineering harness for routing, verification, and failure recovery while preserving agent autonomy.",
5
5
  "author": {
6
6
  "name": "Miya Daniel",
@@ -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.16.2",
4
+ "version": "0.16.4",
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",
@@ -2,7 +2,8 @@
2
2
 
3
3
  Issue #85 Phase 3 makes the stage map a machine-readable execution contract.
4
4
  The router still chooses only the execution topology. Fable owns the stage map,
5
- model selector, worker briefs, stage audit, replan budget, and cold verifier.
5
+ model selector, worker briefs, stage audit, advisory replan limits, and cold
6
+ verifier.
6
7
  Phase 4 adds an optional bounded ensemble modifier without creating a new base
7
8
  topology.
8
9
 
@@ -4,7 +4,7 @@ description: "Stage large, multi-source or multi-session tasks through a written
4
4
  license: Apache-2.0
5
5
  metadata:
6
6
  author: Miya Daniel
7
- version: 0.16.2
7
+ version: 0.16.3
8
8
  ---
9
9
 
10
10
  # Fable Mode (v3)
@@ -77,11 +77,12 @@ spawn workers.
77
77
 
78
78
  For `fable-parallel`, spawn only stages in the same validated execution batch;
79
79
  never invent an additional parallel edge. A stage depending on another stage is
80
- not in the same ready batch. Never exceed `workflowPlan.limits.maxWorkers`. The router plan is the numeric
81
- source of truth; `workflow-plan-consumer.js` chunks ready sets to that cap and
82
- runtime worker leases enforce it when the host exposes stable worker IDs. For
83
- other Fable strategies, serialize the returned batches unless a later validated
84
- plan says otherwise.
80
+ not in the same ready batch. Treat `workflowPlan.limits.maxWorkers` as a
81
+ planning cap you are expected to respect: it is advisory. `workflow-plan-consumer.js`
82
+ returns every dependency-ready stage without chunking to that cap, and nothing
83
+ leases or counts workers at runtime, so exceeding it is your own judgement call,
84
+ not a blocked action. For other Fable strategies, serialize the returned batches
85
+ unless a later validated plan says otherwise.
85
86
 
86
87
  **3. Verify with a check that can fail — external artifacts only.** Each stage
87
88
  defines a pass condition an external artifact satisfies: a test that runs, a file
@@ -7,7 +7,7 @@ description: >-
7
7
  license: Apache-2.0
8
8
  metadata:
9
9
  author: Miya Daniel
10
- version: 0.16.2
10
+ version: 0.16.3
11
11
  ---
12
12
 
13
13
  # Execution Guardrails
@@ -4,7 +4,7 @@ description: "Run staged fable work on Haiku for bulk mechanical tasks with expl
4
4
  license: Apache-2.0
5
5
  metadata:
6
6
  author: Miya Daniel
7
- version: 0.16.2
7
+ version: 0.16.3
8
8
  ---
9
9
 
10
10
  # Fable Mode — Haiku
@@ -4,7 +4,7 @@ description: "Run staged fable orchestration on Opus for cross-stage synthesis,
4
4
  license: Apache-2.0
5
5
  metadata:
6
6
  author: Miya Daniel
7
- version: 0.16.2
7
+ version: 0.16.3
8
8
  ---
9
9
 
10
10
  # Fable Mode — Opus
@@ -4,7 +4,7 @@ description: "Run staged fable work on Sonnet for non-trivial implementation, re
4
4
  license: Apache-2.0
5
5
  metadata:
6
6
  author: Miya Daniel
7
- version: 0.16.2
7
+ version: 0.16.3
8
8
  ---
9
9
 
10
10
  # Fable Mode — Sonnet
@@ -4,7 +4,7 @@ description: "Route software/project work through the Harness kernel: classify T
4
4
  license: Apache-2.0
5
5
  metadata:
6
6
  author: Miya Daniel
7
- version: 0.16.2
7
+ version: 0.16.3
8
8
  ---
9
9
 
10
10
  # Harness Everything
@@ -110,7 +110,7 @@ This does not choose a topology and does not itself enforce the gate. Phase 5 ow
110
110
 
111
111
  Examples:
112
112
 
113
- - `objective-verification` and `loop-budget` are mandatory for `iterative-single`;
113
+ - `loop-awareness` and `objective-verification` are mandatory for `iterative-single`, on top of the base `scope-lock`, `verify-before-claim`, and `replan-after-repeated-failure`;
114
114
  - `tdd` and `verification-loop` remain advisory skill suggestions;
115
115
  - `stage-contracts` and `cold-verification` are mandatory for Fable topologies;
116
116
  - `multi-agent-workspace` is suggested only when the selected topology actually requires durable workspace behavior.