harness-everything 0.16.0 → 0.16.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 (111) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/AGENTS.md +2 -2
  4. package/CHANGELOG.md +14 -0
  5. package/README.md +7 -7
  6. package/VERIFICATION.md +3 -3
  7. package/behavioral-evals/PAIRED-BENCHMARK.md +3 -3
  8. package/behavioral-evals/README.md +38 -32
  9. package/behavioral-evals/opencode-hardlock-live.js +6 -290
  10. package/behavioral-evals/opencode-reflection-gate-live.js +342 -0
  11. package/behavioral-evals/paired-benchmark.js +3 -3
  12. package/ci/consistency-check.js +20 -0
  13. package/ci/invariant-routing.test.js +58 -158
  14. package/ci/mechanism-2a-rule-of-3.test.js +73 -138
  15. package/ci/mechanism-2ac-atomic-commit-check.test.js +2 -2
  16. package/ci/mechanism-2af-worktree-isolation.test.js +38 -196
  17. package/ci/mechanism-2ah-workflow-lifecycle.test.js +20 -831
  18. package/ci/mechanism-2ai-workspace-fingerprint-batch.test.js +3 -4
  19. package/ci/mechanism-2b-boundary-guard.test.js +6 -16
  20. package/ci/mechanism-2e-scope-guard.test.js +8 -24
  21. package/ci/mechanism-2f-stop-gate.test.js +21 -75
  22. package/ci/mechanism-2n-opencode-plugin.test.js +13 -28
  23. package/ci/mechanism-31-opencode-hardlock-evidence.test.js +43 -99
  24. package/ci/openai-plugin-package.test.js +8 -8
  25. package/ci/openai-plugin-runtime.test.js +2 -2
  26. package/ci/router-workflow-plan.test.js +25 -6
  27. package/ci/self-evolve-loop.test.js +4 -1
  28. package/ci/workflow-execution-contract.test.js +51 -129
  29. package/ci/workflow-plan-consumers-edge.test.js +1 -1
  30. package/ci/workflow-plan-consumers.test.js +6 -6
  31. package/docs/architecture.md +21 -21
  32. package/docs/enforcement-locks.md +41 -102
  33. package/docs/mechanism-first-skill-mesh.md +2 -2
  34. package/docs/philosophy.md +2 -2
  35. package/docs/platform-capabilities.md +3 -3
  36. package/docs/routing.md +14 -14
  37. package/docs/workflow-runtime.md +80 -110
  38. package/evals/harness-everything/tasks/positive-tier1.yaml +1 -1
  39. package/evals/harness-everything/tasks/positive-tier2.yaml +1 -1
  40. package/evals/harness-everything/tasks/positive-tier3.yaml +1 -1
  41. package/evals/using-git-worktrees/tasks/positive-trigger.yaml +1 -1
  42. package/fable-mode/SKILL.md +1 -1
  43. package/fable-mode/agents/fable-orchestrator.md +7 -6
  44. package/fable-mode/execution-guardrails/SKILL.md +1 -1
  45. package/fable-mode/fable-haiku/SKILL.md +1 -1
  46. package/fable-mode/fable-opus/SKILL.md +1 -1
  47. package/fable-mode/fable-sonnet/SKILL.md +1 -1
  48. package/fable-mode/scripts/workflow-plan-consumer.js +4 -3
  49. package/harness-everything/SKILL.md +11 -11
  50. package/harness-everything/references/router-workflow-plan.md +2 -2
  51. package/harness-everything/references/triage-and-tiers.md +11 -11
  52. package/harness-everything/scripts/kernel-router-core.js +5 -5
  53. package/harness-everything/scripts/kernel-router.js +16 -21
  54. package/harness-everything/scripts/router-contract-core.js +1 -1
  55. package/hooks/hooks.json +10 -23
  56. package/hooks/scripts/atomic-commit-check.js +1 -1
  57. package/hooks/scripts/boundary-guard.js +4 -4
  58. package/hooks/scripts/contract-test.js +8 -11
  59. package/hooks/scripts/depth-guard.js +2 -2
  60. package/hooks/scripts/lib/workflow-runtime.js +24 -402
  61. package/hooks/scripts/rule-of-3-tracker.js +28 -31
  62. package/hooks/scripts/rule-of-3.js +4 -28
  63. package/hooks/scripts/state-persist.js +36 -136
  64. package/hooks/scripts/stop-gate.js +15 -48
  65. package/hooks/scripts/subagent-scope-guard.js +8 -8
  66. package/hooks/scripts/workflow-disposition.js +2 -10
  67. package/hooks/scripts/workflow-gate.js +33 -84
  68. package/hooks/scripts/workflow-mutation-denied.js +3 -15
  69. package/hooks/scripts/workflow-stop-gate.js +23 -38
  70. package/opencode-plugin/README.md +10 -13
  71. package/opencode-plugin/index.mjs +14 -30
  72. package/opencode-plugin/plugin.json +1 -1
  73. package/package.json +3 -2
  74. package/plugins/harness-everything/.codex-plugin/plugin.json +1 -1
  75. package/plugins/harness-everything/hooks/hooks.json +3 -3
  76. package/plugins/harness-everything/hooks/scripts/atomic-commit-check.js +1 -1
  77. package/plugins/harness-everything/hooks/scripts/boundary-guard.js +4 -4
  78. package/plugins/harness-everything/hooks/scripts/contract-test.js +8 -11
  79. package/plugins/harness-everything/hooks/scripts/depth-guard.js +2 -2
  80. package/plugins/harness-everything/hooks/scripts/lib/workflow-runtime.js +24 -402
  81. package/plugins/harness-everything/hooks/scripts/rule-of-3-tracker.js +28 -31
  82. package/plugins/harness-everything/hooks/scripts/rule-of-3.js +4 -28
  83. package/plugins/harness-everything/hooks/scripts/state-persist.js +36 -136
  84. package/plugins/harness-everything/hooks/scripts/stop-gate.js +15 -48
  85. package/plugins/harness-everything/hooks/scripts/subagent-scope-guard.js +8 -8
  86. package/plugins/harness-everything/hooks/scripts/workflow-disposition.js +2 -10
  87. package/plugins/harness-everything/hooks/scripts/workflow-gate.js +33 -84
  88. package/plugins/harness-everything/hooks/scripts/workflow-mutation-denied.js +3 -15
  89. package/plugins/harness-everything/hooks/scripts/workflow-stop-gate.js +23 -38
  90. package/plugins/harness-everything/plugin.json +1 -1
  91. package/plugins/harness-everything/scripts/lib/advisory-text.js +16 -29
  92. package/plugins/harness-everything/skills/fable-mode/SKILL.md +1 -1
  93. package/plugins/harness-everything/skills/fable-mode/agents/fable-orchestrator.md +7 -6
  94. package/plugins/harness-everything/skills/fable-mode/execution-guardrails/SKILL.md +1 -1
  95. package/plugins/harness-everything/skills/fable-mode/fable-haiku/SKILL.md +1 -1
  96. package/plugins/harness-everything/skills/fable-mode/fable-opus/SKILL.md +1 -1
  97. package/plugins/harness-everything/skills/fable-mode/fable-sonnet/SKILL.md +1 -1
  98. package/plugins/harness-everything/skills/fable-mode/scripts/workflow-plan-consumer.js +4 -3
  99. package/plugins/harness-everything/skills/harness-everything/SKILL.md +11 -11
  100. package/plugins/harness-everything/skills/harness-everything/references/router-workflow-plan.md +2 -2
  101. package/plugins/harness-everything/skills/harness-everything/references/triage-and-tiers.md +11 -11
  102. package/plugins/harness-everything/skills/harness-everything/scripts/kernel-router-core.js +5 -5
  103. package/plugins/harness-everything/skills/harness-everything/scripts/kernel-router.js +16 -21
  104. package/plugins/harness-everything/skills/harness-everything/scripts/router-contract-core.js +1 -1
  105. package/plugins/harness-everything/skills/using-git-worktrees/SKILL.md +5 -5
  106. package/plugins/harness-everything/skills/zoom-out/SKILL.md +3 -3
  107. package/plugins/harness-everything/skills/zoom-out/references/circuit-breaker.md +4 -4
  108. package/scripts/lib/advisory-text.js +16 -29
  109. package/using-git-worktrees/SKILL.md +5 -5
  110. package/zoom-out/SKILL.md +3 -3
  111. package/zoom-out/references/circuit-breaker.md +4 -4
@@ -1,13 +1,13 @@
1
- # Harness Enforcement Plugin for opencode
1
+ # Harness Guidance + Rule-of-3 Plugin for opencode
2
2
 
3
- Adds hard enforcement gates for Harness skills in opencode, addressing the
3
+ Adds lifecycle guidance, verification reminders, and the Rule-of-3 zoom-out boundary in opencode, addressing the
4
4
  limitation that skills are otherwise advisory-only on that platform.
5
5
 
6
- > **Evidence boundary:** the plugin is implemented against opencode's real plugin API and covered by deterministic mechanism tests. Live plugin loading remains unverified beyond one scoped surface: retained evidence supports project-scope `.js` loading and edit/verification state on OpenCode 1.18.31 (macOS) — [live-host evidence](../benchmarks/results/live-host/opencode-2026-09-16/README.md). The final snapshot is post-reset (`hardLock: false`, `count: 1`), not a history of the enforcement sequence. Hard lock is only an interactive observation with no retained blocked-tool trace. Reflection was operator-seeded, then agent-rewritten; agent-controlled state deletion resets the breaker, so no durable hard enforcement or behavioral effectiveness is claimed. Global scope, npm-package installation, and other host versions remain unverified. See [`../docs/platform-capabilities.md`](../docs/platform-capabilities.md).
6
+ > **Evidence boundary:** the plugin is implemented against opencode's real plugin API and covered by deterministic mechanism tests. Live plugin loading remains unverified beyond one scoped surface: retained evidence supports project-scope `.js` loading and edit/verification state on OpenCode 1.18.31 (macOS) — [live-host evidence](../benchmarks/results/live-host/opencode-2026-09-16/README.md). The retained snapshot predates #190 and is historical evidence only: its final snapshot was post-reset; the old hard-lock was only an interactive observation, with no retained blocked-tool trace. Current behavior has no permanent post-reflection hard lock; only the third matching verification failure pauses edits for reflection. Reflection was operator-seeded, then agent-rewritten, so no behavioral-effectiveness claim is made. Global scope, npm-package installation, and other host versions remain unverified. See [`../docs/platform-capabilities.md`](../docs/platform-capabilities.md).
7
7
 
8
8
  ## Problem
9
9
 
10
- In Claude Code, Harness hooks ENFORCE rules (hard gate). In opencode, skills
10
+ Harness now keeps workflow/productivity rules advisory on both Claude Code and opencode. Explicit permission boundaries and the third-failure Rule-of-3 reflection are the intentional blocking exceptions. In opencode, skills
11
11
  only SUGGEST rules (soft guidance). This means:
12
12
  - Under pressure, agents can bypass skills
13
13
  - Verification can be skipped
@@ -24,7 +24,7 @@ see issue #37 for how that was found and fixed. **Naming caveat (issue
24
24
  #127):** opencode's discovery glob only matches `*.js`/`*.ts`, so the file
25
25
  must be copied to a `.js` name when installed - see Installation below.
26
26
 
27
- It implements three enforcement mechanisms across opencode's real hooks:
27
+ It implements three lifecycle mechanisms across opencode's real hooks:
28
28
 
29
29
  The module follows opencode's V1 plugin contract directly: the named
30
30
  `HarnessEnforcement` export is an async factory receiving the opencode context
@@ -41,7 +41,7 @@ V1 `(input, output)` shape, including
41
41
  Fires after every `edit`, `write` or `apply_patch` tool call and marks
42
42
  verification as pending.
43
43
 
44
- ### 2. Verification gate (`event`, on `session.idle`)
44
+ ### 2. Verification reminder (`event`, on `session.idle`)
45
45
 
46
46
  opencode has no "before complete" hook to block the way Claude Code's Stop
47
47
  hook does. `session.idle` - fired when the agent's turn ends - is the closest
@@ -52,7 +52,7 @@ and on failure calls `client.session.prompt()` to push a synthetic follow-up
52
52
  message into the session - forcing the agent to keep working instead of
53
53
  actually stopping.
54
54
 
55
- ### 3. Circuit breaker (`tool.execute.before` + the verification gate above)
55
+ ### 3. Rule-of-3 zoom-out boundary (`tool.execute.before` + the verification observer above)
56
56
 
57
57
  Enforces Rule of 3 on repeated verification failures (same failing command +
58
58
  truncated error, not arbitrary tool failures - `tool.execute.after` has no
@@ -62,11 +62,8 @@ normalized success/failure field to key a signature on for tools in general):
62
62
  - the follow-up asks for a tokenized `zoom-out-report.md` artifact with the
63
63
  required reflection sections; the artifact is accepted through the real
64
64
  edit hook and records `lastReflection`
65
- - the same signature failing again after that reflection was recorded
66
- hard-locks the breaker
67
- - once hard-locked, `tool.execute.before` throws on any `edit`/`write`/
68
- `apply_patch` call, blocking further edits until the state file is cleared
69
- or a new session starts
65
+ - after a valid reflection, the signature count resets; another three matching failures trigger another zoom-out
66
+ - `npm run harness:reset` remains an optional manual state clear; a repeated cycle does not create a permanent second-stage lock
70
67
 
71
68
  Idle handling is bounded: after a failed verification, the plugin records that
72
69
  the follow-up is pending and ignores repeated `session.idle` events until a new
@@ -143,7 +140,7 @@ their patch target names the report file.
143
140
  `ci/mechanism-2n-opencode-plugin.test.js` imports `index.mjs` and drives its
144
141
  exported hooks directly with a mock `client`/`event` context - the same shape
145
142
  opencode's plugin loader passes in - covering the edit → idle → follow-up →
146
- reflection-artifact → retry → hard-lock sequence, repeated-idle idempotency,
143
+ reflection-artifact → retry → fresh three-failure cycle, repeated-idle idempotency,
147
144
  session isolation, reset behavior, legacy-state migration, corrupt-state
148
145
  fail-closed behavior, and patch-based reflection writes.
149
146
 
@@ -17,7 +17,7 @@
17
17
  * message via client.session.prompt() to force the agent
18
18
  * to keep going instead of truly stopping.)
19
19
  * verify.js -> inlined into the session.idle handler
20
- * circuit-breaker.js -> tool.execute.before (throws to hard-block edit tools
20
+ * circuit-breaker.js -> tool.execute.before (throws to pause edit tools for the zoom-out boundary
21
21
  * once locked) + failure tracking inside session.idle
22
22
  * compliance.js -> folded into the same state writes, no separate stage
23
23
  *
@@ -50,7 +50,7 @@ function getStateHome() {
50
50
  // Keys state per real workspace (`directory`, which opencode itself resolves
51
51
  // - never a cwd walk) instead of one flat dir shared by every project on the
52
52
  // machine. The pre-fix `~/.harness-state` had no such key at all: a circuit
53
- // breaker trip in one opencode project hard-locked every other one too
53
+ // breaker trip in one opencode project affected every other one too
54
54
  // (issue #42 item #4).
55
55
  function getWorkspaceKey(directory) {
56
56
  let real = resolve(directory)
@@ -162,7 +162,6 @@ function defaultEditState() {
162
162
  function defaultBreakerState() {
163
163
  return {
164
164
  failures: {},
165
- hardLock: false,
166
165
  lastReflection: null,
167
166
  lastReflectionSignature: null,
168
167
  reflectionPending: false,
@@ -177,7 +176,8 @@ function normalizeEditState(state) {
177
176
  }
178
177
 
179
178
  function normalizeBreakerState(state) {
180
- return { ...defaultBreakerState(), ...(state || {}), failures: (state && state.failures) || {} }
179
+ const { hardLock: _retiredHardLock, ...rest } = state || {}
180
+ return { ...defaultBreakerState(), ...rest, failures: (state && state.failures) || {} }
181
181
  }
182
182
 
183
183
  function isRecord(value) {
@@ -193,7 +193,6 @@ function loadBreakerState(file) {
193
193
  if (
194
194
  !isRecord(state) ||
195
195
  (state.failures !== undefined && !isRecord(state.failures)) ||
196
- (state.hardLock !== undefined && typeof state.hardLock !== "boolean") ||
197
196
  (state.reflectionPending !== undefined && typeof state.reflectionPending !== "boolean") ||
198
197
  !finiteOrNull(state.lastReflection) ||
199
198
  !finiteOrNull(state.reflectionRequestedAt) ||
@@ -209,7 +208,8 @@ function loadBreakerState(file) {
209
208
  ) throw new Error("invalid breaker state shape")
210
209
  return normalizeBreakerState(state)
211
210
  } catch {
212
- throw new Error(`Harness circuit breaker state is corrupt: "${file}" cannot be read safely.`)
211
+ console.warn(`Harness: ignoring corrupt circuit-breaker state at "${file}" and starting fresh.`)
212
+ return defaultBreakerState()
213
213
  }
214
214
  }
215
215
 
@@ -246,6 +246,11 @@ function completeReflection(breakerFile, reportFile) {
246
246
  const completedAt = Math.max(Date.now(), (breaker.reflectionRequestedAt || 0) + 1)
247
247
  breaker.lastReflection = completedAt
248
248
  breaker.lastReflectionSignature = breaker.reflectionSignature
249
+ if (breaker.reflectionSignature && breaker.failures[breaker.reflectionSignature]) {
250
+ breaker.failures[breaker.reflectionSignature].count = 0
251
+ breaker.failures[breaker.reflectionSignature].firstSeen = completedAt
252
+ breaker.failures[breaker.reflectionSignature].lastSeen = completedAt
253
+ }
249
254
  breaker.reflectionPending = false
250
255
  breaker.reflectionRequestedAt = null
251
256
  breaker.reflectionToken = null
@@ -304,9 +309,8 @@ function runVerification(cwd) {
304
309
 
305
310
  /**
306
311
  * Records a verification failure against the circuit breaker and returns the
307
- * action to take: allow (with retries remaining), force_reflection (3rd
308
- * failure on this signature), or hard_lock (same signature repeats after a
309
- * reflection was recorded).
312
+ * action to take: allow (with retries remaining) or force_reflection on the
313
+ * third matching failure. Completing reflection resets that signature's count.
310
314
  */
311
315
  function tripBreaker(breakerFile, signature) {
312
316
  const breaker = loadBreakerState(breakerFile)
@@ -319,15 +323,6 @@ function tripBreaker(breakerFile, signature) {
319
323
  entry.lastSeen = Date.now()
320
324
 
321
325
  if (entry.count >= 3) {
322
- if (
323
- breaker.lastReflection &&
324
- breaker.lastReflection > entry.firstSeen &&
325
- breaker.lastReflectionSignature === signature
326
- ) {
327
- breaker.hardLock = true
328
- saveJSON(breakerFile, breaker)
329
- return { action: "hard_lock", count: entry.count }
330
- }
331
326
  if (!breaker.reflectionPending) {
332
327
  breaker.reflectionPending = true
333
328
  breaker.reflectionRequestedAt = Date.now()
@@ -610,12 +605,6 @@ export const HarnessEnforcement = async ({ client, directory }) => {
610
605
  if (!EDIT_TOOLS.has(input.tool)) return
611
606
  const { breakerFile, reflectionFile } = pathsFor(input.sessionID)
612
607
  const breaker = loadBreakerState(breakerFile)
613
- if (breaker.hardLock) {
614
- throw new Error(
615
- `Harness circuit breaker hard-locked after a repeat failure post-reflection. ` +
616
- `Delete "${breakerFile}" or start a new session to reset.`,
617
- )
618
- }
619
608
  if (breaker.reflectionPending && !isReflectionWrite(input, output, reflectionFile)) {
620
609
  throw new Error(
621
610
  `Harness reflection is required before another code edit. ` +
@@ -715,12 +704,7 @@ export const HarnessEnforcement = async ({ client, directory }) => {
715
704
  saveJSON(editStateFile, state)
716
705
 
717
706
  let text
718
- if (trip.action === "hard_lock") {
719
- text =
720
- `Harness: same verification failure ("${failing.command}") returned after a reflection was ` +
721
- `already recorded. The circuit breaker is now hard-locked - edits are blocked until it is reset.`
722
- recordCompliance(complianceFile, (c) => c.circuitBreakerTrips++)
723
- } else if (trip.action === "force_reflection") {
707
+ if (trip.action === "force_reflection") {
724
708
  const { stateDir } = pathsFor(activeSession)
725
709
  text =
726
710
  `Harness: "${failing.command}" has now failed 3 times with the same error. Stop and reflect ` +
@@ -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.0",
4
+ "version": "0.16.2",
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.0",
3
+ "version": "0.16.2",
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,7 +40,8 @@
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",
43
+ "eval:opencode:reflection-gate-live": "node behavioral-evals/opencode-reflection-gate-live.js run",
44
+ "eval:opencode:hardlock-live": "node behavioral-evals/opencode-reflection-gate-live.js run",
44
45
  "eval:paired": "node behavioral-evals/paired-benchmark.js run",
45
46
  "eval:paired:summarize": "node behavioral-evals/paired-benchmark.js summarize",
46
47
  "test:ab": "node ci/ab-test-harness.js validate",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "harness-everything",
3
- "version": "0.16.0",
3
+ "version": "0.16.2",
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",
@@ -39,7 +39,7 @@
39
39
  "command": "node \"${PLUGIN_ROOT}/hooks/scripts/workflow-gate.js\"",
40
40
  "commandWindows": "node \"${PLUGIN_ROOT}\\hooks\\scripts\\workflow-gate.js\"",
41
41
  "timeout": 15,
42
- "statusMessage": "Checking Harness workflow and worktree-isolation contract"
42
+ "statusMessage": "Reviewing Harness workflow/worktree guidance"
43
43
  }
44
44
  ]
45
45
  },
@@ -248,14 +248,14 @@
248
248
  "command": "node \"${PLUGIN_ROOT}/hooks/scripts/workflow-stop-gate.js\"",
249
249
  "commandWindows": "node \"${PLUGIN_ROOT}\\hooks\\scripts\\workflow-stop-gate.js\"",
250
250
  "timeout": 15,
251
- "statusMessage": "Checking Harness workflow completion gate"
251
+ "statusMessage": "Reviewing verification reminder"
252
252
  },
253
253
  {
254
254
  "type": "command",
255
255
  "command": "node \"${PLUGIN_ROOT}/hooks/scripts/stop-gate.js\"",
256
256
  "commandWindows": "node \"${PLUGIN_ROOT}\\hooks\\scripts\\stop-gate.js\"",
257
257
  "timeout": 15,
258
- "statusMessage": "Checking Harness verification gate"
258
+ "statusMessage": "Reviewing verification reminder"
259
259
  }
260
260
  ]
261
261
  },
@@ -143,7 +143,7 @@ function main(payload) {
143
143
  const changedFiles = statusRaw.split('\n').length;
144
144
  console.error(`[Atomic Commit Check] ${state.editCount} edits since the last commit (${changedFiles} files currently changed).`);
145
145
  console.error('If a logically complete chunk of work is done, commit it now before continuing - large uncommitted diffs are harder to review and harder to recover from.');
146
- process.exit(2);
146
+ process.exit(0);
147
147
  }
148
148
 
149
149
  process.exit(0);
@@ -25,10 +25,10 @@ process.stdin.on('end', () => {
25
25
  if (filePath && !input.limit && fs.existsSync(filePath)) {
26
26
  const stat = fs.statSync(filePath);
27
27
  if (stat.isFile() && stat.size > MAX_BYTES_WITHOUT_LIMIT) {
28
- console.error(`[Boundary Guard] BLOCKED: "${filePath}" is ${(stat.size / 1024).toFixed(0)}KB.`);
28
+ console.error(`[Boundary Reminder]: "${filePath}" is ${(stat.size / 1024).toFixed(0)}KB.`);
29
29
  console.error(`Reading a file this large in one call risks context bloat and "lost in the middle" degradation.`);
30
30
  console.error(`Re-issue the Read with an explicit "offset"/"limit" to pull a targeted slice, or use Grep to locate the relevant section first.`);
31
- process.exit(2);
31
+ process.exit(0);
32
32
  }
33
33
  }
34
34
  }
@@ -41,10 +41,10 @@ process.stdin.on('end', () => {
41
41
  return asPathSegment.test(searchPath) || asPathSegment.test(pattern);
42
42
  });
43
43
  if (hitsNoiseDir) {
44
- console.error(`[Boundary Guard] BLOCKED: search targets a noise directory (${NOISE_DIRS.join(', ')}).`);
44
+ console.error(`[Boundary Reminder]: search targets a noise directory (${NOISE_DIRS.join(', ')}).`);
45
45
  console.error(`These produce huge, low-signal result sets and rarely contain what you're actually looking for.`);
46
46
  console.error(`Scope the search to source directories instead, or state explicitly why this directory must be searched.`);
47
- process.exit(2);
47
+ process.exit(0);
48
48
  }
49
49
  }
50
50
 
@@ -22,7 +22,7 @@ const {
22
22
  listRunContracts,
23
23
  getWorkerId,
24
24
  } = require('./lib/fable-contracts');
25
- const { loadWorkflow, matchingRun, recordBudgetEvent } = require('./lib/workflow-runtime');
25
+ const { loadWorkflow, matchingRun } = require('./lib/workflow-runtime');
26
26
  const { createLearningOpportunity } = require('./lib/learning-opportunity');
27
27
 
28
28
  function resultState(payload) {
@@ -119,7 +119,7 @@ process.stdin.on('end', () => {
119
119
  if (resolution.ambiguous || !resolution.match) {
120
120
  console.error(`[Contract Test] Ambiguous Fable check command matched ${runMatches.length} active run contract(s): ${command}`);
121
121
  console.error('No contract was mutated. Correlate the worker/session to one run before accepting this check.');
122
- process.exit(2);
122
+ process.exit(0);
123
123
  }
124
124
 
125
125
  const entry = resolution.match;
@@ -127,14 +127,14 @@ process.stdin.on('end', () => {
127
127
  const worker = getWorkerId(payload);
128
128
  if (!worker || (entry.contract.workerId && worker !== entry.contract.workerId)) {
129
129
  console.error('[Contract Test] Active workflow check lacks a matching observed worker identity.');
130
- process.exit(2);
130
+ process.exit(0);
131
131
  }
132
132
  for (const id of entry.contract.dependsOn || []) {
133
133
  const dependency = JSON.parse(fs.readFileSync(path.join(entry.runRoot, 'contracts', `${id}.json`), 'utf8'));
134
134
  const escaped = workflowContext.workflow.escapes?.some(item => item.stageId === id && item.runId === entry.contract.runId);
135
135
  if (dependency.status !== 'pass' && !escaped) {
136
136
  console.error('[Contract Test] Dependency has not passed: ' + id);
137
- process.exit(2);
137
+ process.exit(0);
138
138
  }
139
139
  }
140
140
  }
@@ -164,12 +164,9 @@ process.stdin.on('end', () => {
164
164
  }
165
165
  console.log(`[Contract Test] ${contract.planId}/${contract.runId}/${contract.stageId}: ${contract.status.toUpperCase()} ${contract.checkCommand}`);
166
166
  if (contract.status === 'fail') {
167
- if (workflowContext.workflow?.workflowId) {
168
- recordBudgetEvent(workflowContext, 'revision', { evidence: `${contract.stageId}:${contract.evidence || 'verification-failed'}` });
169
- }
170
167
  console.error(`Evidence: ${contract.evidence || '(no output captured)'}`);
171
- console.error(`Do not build on this stage's output until it passes. Artifact: ${contract.outputPath || '(no path recorded)'}`);
172
- process.exit(2);
168
+ console.error(`Review this failed stage before relying on its output. Artifact: ${contract.outputPath || '(no path recorded)'}`);
169
+ process.exit(0);
173
170
  }
174
171
  process.exit(0);
175
172
  }
@@ -179,12 +176,12 @@ process.stdin.on('end', () => {
179
176
  const legacy = resolveLegacyContract(stateRoot, command, payload);
180
177
  if (legacy && legacy.ambiguous) {
181
178
  console.error(`[Contract Test] Ambiguous legacy stage contracts matched: ${command}`);
182
- process.exit(2);
179
+ process.exit(0);
183
180
  }
184
181
  if (legacy && legacy.failed) {
185
182
  console.error(`[Contract Test] Legacy stage "${legacy.contract.stageId}" FAILED its named check: ${legacy.contract.checkCommand}`);
186
183
  console.error(`Evidence: ${legacy.contract.evidence || '(no output captured)'}`);
187
- process.exit(2);
184
+ process.exit(0);
188
185
  }
189
186
  process.exit(0);
190
187
  } catch (_) {
@@ -52,10 +52,10 @@ process.stdin.on('end', () => {
52
52
  });
53
53
 
54
54
  if (!wasRead) {
55
- console.error(`[Depth Guard] BLOCKED: "${filePath}" already exists but hasn't been Read in this session.`);
55
+ console.error(`[Depth Reminder]: "${filePath}" already exists but hasn't been Read in this session.`);
56
56
  console.error(`Write() overwrites the whole file - doing that blind risks destroying content you never looked at.`);
57
57
  console.error(`Read the file first (even a quick pass), then retry the Write, or use Edit for a targeted change.`);
58
- process.exit(2);
58
+ process.exit(0);
59
59
  }
60
60
 
61
61
  process.exit(0);