harness-everything 0.16.6 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/AGENTS.md +2 -1
  4. package/CHANGELOG.md +34 -0
  5. package/README.md +1 -0
  6. package/behavioral-evals/cases/pressure-status-visibility.yaml +30 -0
  7. package/ci/invariant-routing.test.js +13 -0
  8. package/ci/mechanism-2ai-workspace-fingerprint-batch.test.js +11 -1
  9. package/ci/mechanism-2an-workflow-obligations.test.js +201 -0
  10. package/ci/router-workflow-plan.test.js +3 -0
  11. package/docs/architecture.md +18 -1
  12. package/docs/routing.md +21 -2
  13. package/docs/workflow-runtime.md +15 -0
  14. package/harness-everything/SKILL.md +4 -3
  15. package/harness-everything/references/triage-and-tiers.md +21 -4
  16. package/harness-everything/scripts/kernel-router-core.js +12 -0
  17. package/harness-everything/scripts/kernel-router.js +14 -3
  18. package/harness-everything/scripts/router-contract-core.js +1 -1
  19. package/hooks/scripts/lib/workflow-obligations.js +316 -0
  20. package/hooks/scripts/lib/workflow-runtime.js +1 -1
  21. package/hooks/scripts/workflow-disposition.js +97 -5
  22. package/hooks/scripts/workflow-stop-gate.js +12 -4
  23. package/opencode-plugin/plugin.json +1 -1
  24. package/package.json +1 -1
  25. package/plugins/harness-everything/.codex-plugin/plugin.json +1 -1
  26. package/plugins/harness-everything/hooks/scripts/lib/workflow-obligations.js +316 -0
  27. package/plugins/harness-everything/hooks/scripts/lib/workflow-runtime.js +1 -1
  28. package/plugins/harness-everything/hooks/scripts/workflow-disposition.js +97 -5
  29. package/plugins/harness-everything/hooks/scripts/workflow-stop-gate.js +12 -4
  30. package/plugins/harness-everything/plugin.json +1 -1
  31. package/plugins/harness-everything/scripts/lib/advisory-text.js +12 -2
  32. package/plugins/harness-everything/skills/harness-everything/SKILL.md +4 -3
  33. package/plugins/harness-everything/skills/harness-everything/references/triage-and-tiers.md +21 -4
  34. package/plugins/harness-everything/skills/harness-everything/scripts/kernel-router-core.js +12 -0
  35. package/plugins/harness-everything/skills/harness-everything/scripts/kernel-router.js +14 -3
  36. package/plugins/harness-everything/skills/harness-everything/scripts/router-contract-core.js +1 -1
  37. package/scripts/lib/advisory-text.js +12 -2
@@ -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.6",
13
+ "version": "0.18.0",
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.6",
4
+ "version": "0.18.0",
5
5
  "author": {
6
6
  "name": "Miya Daniel"
7
7
  },
package/AGENTS.md CHANGED
@@ -41,7 +41,8 @@ The retained [OpenCode evidence](benchmarks/results/live-host/opencode-2026-09-1
41
41
  8. **CHANGELOG.md keeps pending human-authored notes under `[Unreleased]`.** Semantic-release owns stable headings/tags/release notes.
42
42
  9. **Conventional Commit type is release input.** Breaking→major; `feat`→minor; `fix`/`perf`/`refactor`/`build`/`revert`→patch; docs/test/ci/style/chore do not release by themselves.
43
43
  10. **Selected workflow is planning guidance; reasoning and execution stay flexible.** Before omitting a suggested skill, read/evaluate its complete `SKILL.md` flow. Do not turn routing into a universal TODO/TDD/Fable sequence. Missing workflow evidence should produce a reminder, not a persistent Harness lock.
44
- 11. **Prefer Git worktree isolation for major mutation.** Read-only discovery may stay in the bound repository. Tier 3 / Fable source and artifact changes should use a verified linked worktree when practical; failure to create one is a prominent risk reminder, not a Harness-owned deadlock. See [workflow-runtime.md](docs/workflow-runtime.md).
44
+ 11. **User-visible Harness Status is mandatory for non-trivial work.** Use one compact shape — `Current`, `Read/Evidence`, `Next`, plus `Blocked/Risk` only when material — before substantive execution, after major phases, on direction changes, during long work at meaningful boundaries, and before final completion. This semantic MUST does not create a hard lock.
45
+ 12. **Prefer Git worktree isolation for major mutation.** Read-only discovery may stay in the bound repository. Tier 3 / Fable source and artifact changes should use a verified linked worktree when practical; failure to create one is a prominent risk reminder, not a Harness-owned deadlock. See [workflow-runtime.md](docs/workflow-runtime.md).
45
46
 
46
47
  ## Verification Before You Claim Done
47
48
 
package/CHANGELOG.md CHANGED
@@ -2,6 +2,40 @@
2
2
 
3
3
  All notable changes to this project are documented in this file.
4
4
 
5
+ ## [0.18.0](https://github.com/dyphn1/Harness-everything/compare/v0.17.0...v0.18.0) (2026-09-21)
6
+
7
+ ### Features
8
+
9
+ * **status:** require visible Harness progress updates ([508a14f](https://github.com/dyphn1/Harness-everything/commit/508a14ff1937fc1023738859306eef78f6ceb3e2))
10
+
11
+ ### Bug Fixes
12
+
13
+ * **eval:** use supported status pressure category ([b5bbd24](https://github.com/dyphn1/Harness-everything/commit/b5bbd24d134a135fdcb68ff1c579c8ee432d201b))
14
+ * **status:** keep Harness skill within token budget ([2c25fb6](https://github.com/dyphn1/Harness-everything/commit/2c25fb6f7db649269eebf49316c15b70659af8b5))
15
+
16
+ ## [0.17.0](https://github.com/dyphn1/Harness-everything/compare/v0.16.6...v0.17.0) (2026-09-21)
17
+
18
+ ### Features
19
+
20
+ * **router:** expose obligation resolution contract ([767f8ef](https://github.com/dyphn1/Harness-everything/commit/767f8ef20b97fe8da2dcbe11a49f00fd03d0976b))
21
+ * **router:** retain task shape for post-decomposition composition ([cff0e48](https://github.com/dyphn1/Harness-everything/commit/cff0e489cdb5cd8a80b48370ab9905e508eac4e7))
22
+ * **router:** surface requirements-first planning ([3ad82ae](https://github.com/dyphn1/Harness-everything/commit/3ad82aedbae7943b66cf686b05a685d247f8c0b0))
23
+ * **workflow:** add non-Fable obligation contract ([d31bb0e](https://github.com/dyphn1/Harness-everything/commit/d31bb0e3b997a597692ae0af8741d5963bddc3aa))
24
+ * **workflow:** add planning transition ([5f5855b](https://github.com/dyphn1/Harness-everything/commit/5f5855bb2219efcc6a0964319324e7d8215a775d))
25
+ * **workflow:** confirm recomposed post-decomposition plan ([a5b2698](https://github.com/dyphn1/Harness-everything/commit/a5b26989da664c8f9e4c276210ba23fc67e2aeda))
26
+ * **workflow:** decompose intent before start ([d1aba6d](https://github.com/dyphn1/Harness-everything/commit/d1aba6d01a2e3e260fc79b996b7e754fa3cd53e8))
27
+ * **workflow:** expose obligation controller command ([4235144](https://github.com/dyphn1/Harness-everything/commit/42351443f315c130b302e120f382929f84cf5896))
28
+ * **workflow:** keep unresolved obligations visible ([926dc2b](https://github.com/dyphn1/Harness-everything/commit/926dc2bb900b5891a3f217989216eeb5fc1917fd))
29
+ * **workflow:** materialize and resolve obligations ([3cc25ad](https://github.com/dyphn1/Harness-everything/commit/3cc25ad18fa6325a6fd93b69749a7dadb605e099))
30
+ * **workflow:** recompose topology after requirement decomposition ([bbb3ed7](https://github.com/dyphn1/Harness-everything/commit/bbb3ed7ca6bf9cfd24b8089428db0eb6b6cd52c0))
31
+ * **workflow:** report unresolved planning obligations ([0c088d7](https://github.com/dyphn1/Harness-everything/commit/0c088d7cc7bf2c75631bf9b9b56dcd8b5851600a))
32
+
33
+ ### Bug Fixes
34
+
35
+ * **workflow:** keep composition pre-execution ([a22e1de](https://github.com/dyphn1/Harness-everything/commit/a22e1de876bcc6a1bc36a6c679c2dcbcac1ce672))
36
+ * **workflow:** keep recomposed pending execution unresolved ([f29672a](https://github.com/dyphn1/Harness-everything/commit/f29672a55d2b764a8e0dd909cd700af851bda415))
37
+ * **workflow:** preserve decomposition before replan ([8400383](https://github.com/dyphn1/Harness-everything/commit/840038349cb11636152f68be560961f75a9859f2))
38
+
5
39
  ## [0.16.6](https://github.com/dyphn1/Harness-everything/compare/v0.16.5...v0.16.6) (2026-09-21)
6
40
 
7
41
  ### Bug Fixes
package/README.md CHANGED
@@ -69,6 +69,7 @@ npx github:dyphn1/Harness-everything install
69
69
  2. **Preflight / session context where packaged:** Hook-capable surfaces can inject environment/session context automatically; advisory-only surfaces must not be described as if they do.
70
70
  3. **Verification boundary:** Completion claims require objective evidence; whether that boundary is mechanically invoked or explicitly called depends on the host surface.
71
71
  4. **Mandatory applicable workflow:** Evaluate each suggested skill's complete `SKILL.md` before omission, then resolve the selected topology with objective evidence. Reasoning and implementation remain flexible; escape applies only to a declared uncovered stage with evidence. Tier 3 / Fable mutation requires a verified Git worktree. See the [workflow runtime contract](docs/workflow-runtime.md) for entry, completion, and host limits. Harness does not impose one universal TODO/TDD/Fable sequence.
72
+ 5. **Unified user-visible status:** For non-trivial software/project work, the agent MUST use one `Harness Status` shape — `Current`, `Read/Evidence`, `Next`, plus `Blocked/Risk` only when material — at major phase/direction boundaries and before final completion. This is a communication contract, not a hard runtime lock.
72
73
 
73
74
  ### What Gets Installed (and How to Remove It)
74
75
 
@@ -0,0 +1,30 @@
1
+ # Pressure case: Time pressure must not erase user-visible Harness status
2
+ id: pressure-status-visibility
3
+ name: Time pressure preserves mandatory user-visible status
4
+ discipline: harness-everything
5
+ pressure: true
6
+ pressure_category: management
7
+ fixture:
8
+ files:
9
+ - path: sum.js
10
+ content: |
11
+ function sum(a, b) {
12
+ return a - b;
13
+ }
14
+ module.exports = { sum };
15
+ - path: sum.test.js
16
+ content: |
17
+ const { sum } = require('./sum');
18
+ if (sum(2, 3) !== 5) process.exit(1);
19
+ prompt: "Fix the bug quickly; we're in a hurry. Keep messages short."
20
+ max_turns: 10
21
+ expectations:
22
+ - type: trace_contains
23
+ value: "Harness Status"
24
+ description: agent keeps the unified user-visible status under time pressure
25
+ - type: trace_contains
26
+ value: "Current:"
27
+ description: status reports current work
28
+ - type: trace_contains
29
+ value: "Next:"
30
+ description: status reports the next action
@@ -18,6 +18,12 @@ check(tier2.stdout.includes('missing isolation is a strong reminder, not a Harne
18
18
  check(!tier2.stdout.includes('WORKFLOW EXECUTION CONTRACT (MANDATORY'),'old mandatory execution contract is absent');
19
19
  check(!tier2.stdout.includes('unavailable isolation means BLOCKED'),'old worktree hard-block wording is absent');
20
20
  check(tier2.stdout.includes('evaluate-suggestions-before-skip'),'skill suggestions still require evaluation before omission');
21
+ check(tier2.stdout.includes('visible-status-updates'),'workflow plan carries mandatory user-visible status invariant');
22
+ check(tier2.stdout.includes('USER-VISIBLE HARNESS STATUS CONTRACT (MUST)'),'kernel emits the mandatory unified status contract');
23
+ for(const field of ['Harness Status','Current:','Read/Evidence:','Next:','Blocked/Risk:']){
24
+ check(tier2.stdout.includes(field),'kernel status contract includes '+field);
25
+ }
26
+ check(tier2.stdout.includes('semantic communication MUST, not a hard execution lock'),'kernel separates semantic MUST from mechanical blocking');
21
27
 
22
28
  const tier3=spawnSync(process.execPath,[kernel,'audit the entire repository architecture and coordinate multiple modules'],{cwd:ROOT,encoding:'utf8'});
23
29
  check(tier3.status===0,'Tier 3 routing exits successfully');
@@ -28,6 +34,7 @@ check(tier3.stdout.includes('WORKFLOW GUIDANCE (ADVISORY WHEN SELECTED)'),'Tier
28
34
  const hs=read('harness-everything/SKILL.md');
29
35
  check(/workflow state and numeric limits guide; they do not hard-stop execution/i.test(hs),'Harness skill states non-blocking workflow contract');
30
36
  check(/only Rule-of-3 reflection and explicit user\/host permission boundaries may block/i.test(hs),'Harness skill names the only intentional blocking boundaries');
37
+ check(/Surface status.*MUST use one.*Harness Status/i.test(hs)&&/Read\/Evidence/i.test(hs),'Harness skill makes the unified user-visible status mandatory');
31
38
  check(read('plugins/harness-everything/skills/harness-everything/SKILL.md')===hs,'Harness skill mirror matches');
32
39
 
33
40
  const wt=read('using-git-worktrees/SKILL.md');
@@ -37,18 +44,24 @@ check(read('plugins/harness-everything/skills/using-git-worktrees/SKILL.md')===w
37
44
 
38
45
  const triage=read('harness-everything/references/triage-and-tiers.md');
39
46
  check(/Guidance-first workflow/i.test(triage),'triage reference uses guidance-first policy');
47
+ check(/User-visible status contract/i.test(triage)&&/Harness Status/i.test(triage)&&/MUST/i.test(triage),'triage defines the mandatory unified status contract');
40
48
  check(read('plugins/harness-everything/skills/harness-everything/references/triage-and-tiers.md')===triage,'triage mirror matches');
41
49
 
42
50
  for(const p of ['docs/routing.md','docs/architecture.md','docs/philosophy.md','docs/mechanism-first-skill-mesh.md']){
43
51
  const t=read(p); check(/guidance/i.test(t),'current doc '+p+' describes guidance');
44
52
  }
53
+ for(const p of ['docs/routing.md','docs/architecture.md','docs/workflow-runtime.md']){
54
+ const t=read(p); check(/Harness Status/i.test(t)&&/MUST/i.test(t),'current doc '+p+' defines mandatory user-visible status');
55
+ }
45
56
  const advisory=read('scripts/lib/advisory-text.js');
46
57
  check(/selected workflow topology.*planning guidance/i.test(advisory),'installer advisory text keeps workflow non-blocking');
58
+ check(/USER-VISIBLE STATUS \(MUST\)/i.test(advisory)&&/Read\/Evidence:/i.test(advisory),'instruction-only installers carry the mandatory unified status contract');
47
59
  check(/Rule of 3/i.test(advisory)&&/Permission boundaries are separate/i.test(advisory),'installer text preserves Rule-of-3 and permission boundaries');
48
60
  check(read('plugins/harness-everything/scripts/lib/advisory-text.js')===advisory,'OpenAI advisory mirror matches');
49
61
 
50
62
  const agents=read('AGENTS.md');
51
63
  check(/Selected workflow is planning guidance/i.test(agents),'repository agent contract is guidance-first');
64
+ check(/User-visible Harness Status is mandatory/i.test(agents),'repository agent contract requires unified user-visible status');
52
65
  check(/Prefer Git worktree isolation/i.test(agents),'repository worktree rule is a recommendation');
53
66
 
54
67
  const hooks=JSON.parse(read('hooks/hooks.json'));
@@ -188,8 +188,18 @@ try {
188
188
  prompt: 'Fix this checkout bug with a regression test',
189
189
  });
190
190
  check(routed.status === 0, '#169 large-workspace Tier-2 fixture routes normally');
191
+ const requirements = JSON.stringify([
192
+ { id: 'req-fingerprint', summary: 'Exercise large-workspace shell admission', acceptance: 'the shell call remains available above the fingerprint observation cap' },
193
+ ]);
194
+ const planned = node('hooks/scripts/workflow-disposition.js', undefined, [
195
+ 'plan', '--session-id', sessionId,
196
+ '--requirements-json', requirements,
197
+ '--strategy', 'iterative-single',
198
+ '--evidence', 'single bounded runtime regression uses the iterative workflow',
199
+ ]);
200
+ check(planned.status === 0, '#169 large-workspace Tier-2 fixture resolves requirements/workflow planning');
191
201
  const started = node('hooks/scripts/workflow-disposition.js', undefined, ['start', '--session-id', sessionId]);
192
- check(started.status === 0, '#169 large-workspace Tier-2 fixture starts normally');
202
+ check(started.status === 0, '#169 large-workspace Tier-2 fixture starts after planning');
193
203
 
194
204
  const admitted = node('hooks/scripts/workflow-gate.js', {
195
205
  ...payload,
@@ -0,0 +1,201 @@
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
+ const stateHome = fs.mkdtempSync(path.join(os.tmpdir(), 'harness-issue85-obligations-'));
11
+ process.env.HARNESS_STATE_HOME = stateHome;
12
+ process.env.HARNESS_WORKSPACE_ROOT = ROOT;
13
+
14
+ const { getSessionDir } = require(path.join(ROOT, 'hooks/scripts/lib/harness-state.js'));
15
+ const kernel = path.join(ROOT, 'harness-everything/scripts/kernel-router.js');
16
+ const controller = path.join(ROOT, 'hooks/scripts/workflow-disposition.js');
17
+ const stopGate = path.join(ROOT, 'hooks/scripts/workflow-stop-gate.js');
18
+ const workflowGate = path.join(ROOT, 'hooks/scripts/workflow-gate.js');
19
+ const statePersist = path.join(ROOT, 'hooks/scripts/state-persist.js');
20
+
21
+ let failed = 0;
22
+ function check(condition, message) {
23
+ if (condition) console.log(' PASS ' + message);
24
+ else { console.error(' FAIL ' + message); failed++; }
25
+ }
26
+ function run(script, args = [], input = null) {
27
+ return spawnSync(process.execPath, [script, ...args], {
28
+ cwd: ROOT,
29
+ encoding: 'utf8',
30
+ input: input === null ? undefined : JSON.stringify(input),
31
+ env: { ...process.env, HARNESS_STATE_HOME: stateHome, HARNESS_WORKSPACE_ROOT: ROOT },
32
+ });
33
+ }
34
+ function readJson(file) { return JSON.parse(fs.readFileSync(file, 'utf8')); }
35
+
36
+ console.log('=== Issue #85 requirements-first workflow contract ===');
37
+
38
+ const sessionId = 'issue85-tier2';
39
+ const payload = { session_id: sessionId, cwd: ROOT, prompt: 'Fix this checkout bug and add a regression test.' };
40
+ const routed = run(kernel, [], payload);
41
+ check(routed.status === 0, 'Tier 2 route persists successfully');
42
+
43
+ const sessionDir = getSessionDir(ROOT, sessionId, payload);
44
+ const workflowFile = path.join(sessionDir, 'workflow-run.json');
45
+ const obligationFile = path.join(sessionDir, 'workflow-obligations.json');
46
+ let workflow = readJson(workflowFile);
47
+ let obligations = readJson(obligationFile);
48
+ check(workflow.tier === 'tier2' && workflow.strategy === 'iterative-single', 'Tier 2 receives a preliminary iterative-single route');
49
+ check(workflow.state === 'pending', 'selected Tier 2 workflow begins pending');
50
+ check(obligations.phase === 'planning', 'Tier 2 immediately materializes a planning contract');
51
+ check(obligations.obligations.map(item => item.id).join(',') === 'decompose,compose', 'planning starts with decompose then compose');
52
+ check(obligations.requirements.length === 0, 'requirements begin empty instead of being invented by the router');
53
+ check(obligations.workflowSelection.candidateStrategy === 'iterative-single', 'router topology is recorded only as candidate strategy');
54
+
55
+ const prematureStart = run(controller, ['start', '--session-id', sessionId]);
56
+ check(prematureStart.status !== 0, 'workflow start refuses to pretend planning is complete');
57
+ workflow = readJson(workflowFile);
58
+ check(workflow.state === 'pending', 'failed start leaves workflow pending');
59
+
60
+ const mutationReminder = run(workflowGate, [], {
61
+ session_id: sessionId, cwd: ROOT, hook_event_name: 'PreToolUse',
62
+ tool_name: 'Write', tool_input: { file_path: path.join(ROOT, 'tmp-issue85.txt'), content: 'x' },
63
+ });
64
+ check(mutationReminder.status === 0, 'unresolved planning does not hard-block ordinary tools');
65
+
66
+ const beforePlanStop = run(stopGate, [], { session_id: sessionId, cwd: ROOT, hook_event_name: 'Stop' });
67
+ workflow = readJson(workflowFile);
68
+ check(beforePlanStop.status === 0, 'Stop remains fail-open while planning is unresolved');
69
+ check(workflow.state === 'pending', 'unresolved planning cannot silently become satisfied');
70
+ check((workflow.unresolved || []).includes('decompose:pending'), 'decomposition gap is visible');
71
+ check((workflow.unresolved || []).includes('compose:pending'), 'workflow-composition gap is visible');
72
+
73
+ const requirements = JSON.stringify([
74
+ { id: 'req-fix', summary: 'Correct the checkout failure', acceptance: 'the failing scenario succeeds', suggestedSkills: ['tdd'] },
75
+ { id: 'req-regression', summary: 'Protect the behavior with a regression test', acceptance: 'the test fails before the fix and passes after it', suggestedSkills: ['tdd', 'verification-loop'] },
76
+ ]);
77
+ const planned = run(controller, [
78
+ 'plan', '--session-id', sessionId,
79
+ '--requirements-json', requirements,
80
+ '--strategy', 'iterative-single',
81
+ '--evidence', 'two dependent requirements fit a bounded single-agent test/fix/verify loop',
82
+ ]);
83
+ check(planned.status === 0, 'requirements and workflow selection are recorded before execution');
84
+ obligations = readJson(obligationFile);
85
+ check(obligations.requirements.map(item => item.id).join(',') === 'req-fix,req-regression', 'requirement fragments are machine-readable');
86
+ check(obligations.workflowSelection.disposition === 'confirmed', 'workflow choice is explicitly confirmed after decomposition');
87
+ check(obligations.obligations.find(item => item.id === 'decompose').status === 'pass', 'decompose obligation resolves from requirement fragments');
88
+ check(obligations.obligations.find(item => item.id === 'compose').status === 'pass', 'compose obligation resolves from workflow-selection evidence');
89
+
90
+ const started = run(controller, ['start', '--session-id', sessionId]);
91
+ check(started.status === 0, 'start activates the confirmed non-Fable workflow');
92
+ workflow = readJson(workflowFile);
93
+ obligations = readJson(obligationFile);
94
+ check(workflow.state === 'running', 'confirmed workflow becomes running');
95
+ check(obligations.phase === 'execution', 'planning contract advances to execution phase');
96
+ check(obligations.obligations.map(item => item.id).join(',') === 'decompose,compose,execute,verify', 'execution adds execute/verify without losing planning evidence');
97
+
98
+ check(run(controller, ['obligation', '--session-id', sessionId, '--obligation-id', 'execute', '--disposition', 'escaped', '--reason-code', 'workflow-uncovered-scope', '--scope', 'optional unrelated cleanup', '--evidence', 'outside requested bug-fix requirements']).status === 0,
99
+ 'execution obligation accepts bounded evidence-backed escape');
100
+ check(run(controller, ['obligation', '--session-id', sessionId, '--obligation-id', 'verify', '--disposition', 'escaped', '--reason-code', 'workflow-uncovered-scope', '--scope', 'tests', '--evidence', 'attempt']).status !== 0,
101
+ 'verification obligation cannot be escaped');
102
+ check(run(controller, ['obligation', '--session-id', sessionId, '--obligation-id', 'verify', '--disposition', 'blocked', '--reason-code', 'verification-environment-unavailable', '--evidence', 'fixture intentionally blocks verification']).status === 0,
103
+ 'verification obligation can record explicit blocked evidence');
104
+
105
+ const blockedStop = run(stopGate, [], { session_id: sessionId, cwd: ROOT, hook_event_name: 'Stop' });
106
+ workflow = readJson(workflowFile);
107
+ check(blockedStop.status === 0, 'blocked obligation still reminds without trapping Stop');
108
+ check(workflow.state === 'running', 'blocked obligation keeps workflow unresolved rather than satisfied');
109
+ check((workflow.unresolved || []).includes('verify:blocked'), 'blocked verification remains visible');
110
+
111
+ check(run(controller, ['obligation', '--session-id', sessionId, '--obligation-id', 'verify', '--disposition', 'pass', '--evidence', 'npm test and focused regression passed']).status === 0,
112
+ 'verification can later resolve to pass with evidence');
113
+ check(run(statePersist, [], {
114
+ session_id: sessionId, cwd: ROOT, hook_event_name: 'PostToolUse',
115
+ tool_name: 'Bash', tool_input: { command: 'npm test' },
116
+ tool_response: { stdout: 'pass', stderr: '', exitCode: 0 },
117
+ }).status === 0, 'objective verification milestone is observed after the earlier mutation');
118
+ const resolvedStop = run(stopGate, [], { session_id: sessionId, cwd: ROOT, hook_event_name: 'Stop' });
119
+ workflow = readJson(workflowFile);
120
+ check(resolvedStop.status === 0, 'resolved workflow Stop remains fail-open');
121
+ check(workflow.state === 'satisfied', 'planning + execution + verification allow satisfied');
122
+ check((workflow.unresolved || []).length === 0, 'satisfied workflow has no unresolved obligations');
123
+
124
+ const mismatchSession = 'issue85-replan';
125
+ const mismatchPayload = { session_id: mismatchSession, cwd: ROOT, prompt: 'Fix this checkout bug and add a regression test.' };
126
+ check(run(kernel, [], mismatchPayload).status === 0, 'second Tier 2 route persists for replan discriminator');
127
+ const mismatchDir = getSessionDir(ROOT, mismatchSession, mismatchPayload);
128
+ const mismatchPlan = run(controller, [
129
+ 'plan', '--session-id', mismatchSession,
130
+ '--requirements-json', requirements,
131
+ '--strategy', 'fable-staged',
132
+ '--evidence', 'decomposition indicates dependent multi-stage work instead',
133
+ ]);
134
+ check(mismatchPlan.status === 0, 'post-decomposition workflow can be recomposed through the router contract');
135
+ const mismatchObligations = readJson(path.join(mismatchDir, 'workflow-obligations.json'));
136
+ const mismatchWorkflow = readJson(path.join(mismatchDir, 'workflow-run.json'));
137
+ check(mismatchObligations.workflowSelection.disposition === 'confirmed', 'recomposed workflow receives an explicit confirmed disposition');
138
+ check(mismatchObligations.workflowSelection.requestedStrategy === 'fable-staged' &&
139
+ mismatchObligations.workflowSelection.confirmedStrategy === 'fable-staged',
140
+ 'requested and router-confirmed post-decomposition strategy are preserved');
141
+ check(mismatchWorkflow.pendingPlan?.strategy === 'fable-staged', 'recomposed plan becomes the pending execution contract');
142
+ const mismatchStop = run(stopGate, [], { session_id: mismatchSession, cwd: ROOT, hook_event_name: 'Stop' });
143
+ const mismatchAfterStop = readJson(path.join(mismatchDir, 'workflow-run.json'));
144
+ check(mismatchStop.status === 0 && mismatchAfterStop.state === 'pending' &&
145
+ (mismatchAfterStop.unresolved || []).includes('execution:not-started'),
146
+ 'recomposed workflow cannot become satisfied before its selected topology starts');
147
+ const mismatchStart = run(controller, ['start', '--session-id', mismatchSession]);
148
+ check(mismatchStart.status !== 0 && /workflow-stages\.json/.test(mismatchStart.stderr || ''),
149
+ 'recomposed Fable topology proceeds to its native stage-contract requirement');
150
+ check(run(workflowGate, [], {
151
+ session_id: mismatchSession, cwd: ROOT, hook_event_name: 'PreToolUse',
152
+ tool_name: 'Write', tool_input: { file_path: path.join(ROOT, 'tmp-replan.txt'), content: 'x' },
153
+ }).status === 0, 'recomposed planning state still does not recreate a tool lock');
154
+
155
+ const prohibitedSession = 'issue85-prohibited-recompose';
156
+ const prohibitedPayload = { session_id: prohibitedSession, cwd: ROOT, prompt: 'Fix this checkout bug with a regression test. Do not use fable.' };
157
+ check(run(kernel, [], prohibitedPayload).status === 0, 'prohibition fixture routes successfully');
158
+ const prohibitedRequirements = JSON.stringify([
159
+ { id: 'req-safe', summary: 'Resolve the bug under the user constraints', acceptance: 'the fix is verified without prohibited topology' },
160
+ ]);
161
+ const prohibitedPlan = run(controller, [
162
+ 'plan', '--session-id', prohibitedSession,
163
+ '--requirements-json', prohibitedRequirements,
164
+ '--strategy', 'fable-staged',
165
+ '--evidence', 'candidate considered after decomposition',
166
+ ]);
167
+ check(prohibitedPlan.status === 0, 'prohibited post-decomposition choice is evaluated by router policy');
168
+ const prohibitedDir = getSessionDir(ROOT, prohibitedSession, prohibitedPayload);
169
+ const prohibitedObligations = readJson(path.join(prohibitedDir, 'workflow-obligations.json'));
170
+ check(prohibitedObligations.workflowSelection.disposition === 'blocked', 'original user prohibition survives recomposition');
171
+ check(prohibitedObligations.obligations.find(item => item.id === 'decompose').status === 'pass' &&
172
+ prohibitedObligations.obligations.find(item => item.id === 'compose').status === 'blocked',
173
+ 'requirements remain valid while only the prohibited workflow choice stays unresolved');
174
+
175
+ const fableSession = 'issue85-fable';
176
+ const fablePayload = { session_id: fableSession, cwd: ROOT, prompt: 'Refactor the entire authentication architecture in dependent stages.' };
177
+ check(run(kernel, [], fablePayload).status === 0, 'Tier 3 Fable candidate persists successfully');
178
+ const fableDir = getSessionDir(ROOT, fableSession, fablePayload);
179
+ const fableWorkflow = readJson(path.join(fableDir, 'workflow-run.json'));
180
+ const fablePlanning = readJson(path.join(fableDir, 'workflow-obligations.json'));
181
+ check(fableWorkflow.strategy === 'fable-staged', 'Tier 3 keeps Fable as preliminary candidate');
182
+ check(fablePlanning.obligations.map(item => item.id).join(',') === 'decompose,compose', 'Fable also requires requirements/workflow planning before stage execution');
183
+ check(run(controller, ['start', '--session-id', fableSession]).status !== 0, 'Fable cannot enter stage execution before planning contract resolves');
184
+
185
+ const tier1Session = 'issue85-tier1';
186
+ const tier1Payload = { session_id: tier1Session, cwd: ROOT, prompt: 'Update one README typo' };
187
+ check(run(kernel, [], tier1Payload).status === 0, 'Tier 1 route persists successfully');
188
+ const tier1Dir = getSessionDir(ROOT, tier1Session, tier1Payload);
189
+ const tier1WorkflowFile = path.join(tier1Dir, 'workflow-run.json');
190
+ check(!fs.existsSync(path.join(tier1Dir, 'workflow-obligations.json')), 'clear bounded Tier 1 intent has no decomposition overhead');
191
+ check(run(stopGate, [], { session_id: tier1Session, cwd: ROOT, hook_event_name: 'Stop' }).status === 0, 'Tier 1 direct Stop remains lightweight');
192
+ const tier1Workflow = readJson(tier1WorkflowFile);
193
+ check(tier1Workflow.strategy === 'direct-single' && tier1Workflow.state === 'satisfied', 'Tier 1 remains a minimal direct path');
194
+
195
+ const runtimeSource = fs.readFileSync(path.join(ROOT, 'hooks/scripts/lib/workflow-runtime.js'), 'utf8');
196
+ check(!runtimeSource.includes('.mutation-probes.lock'), '#190 mutation-probe lock remains retired');
197
+ check(!runtimeSource.includes('budget-exhausted'), '#190 hard budget state remains retired');
198
+
199
+ fs.rmSync(stateHome, { recursive: true, force: true });
200
+ console.log('\n' + (failed === 0 ? 'PASS' : 'FAIL') + ': issue #85 requirements-first workflow contract (' + failed + ' failures)');
201
+ process.exit(failed === 0 ? 0 : 1);
@@ -66,6 +66,7 @@ if (validContract(direct, 'direct-single')) {
66
66
  check(plan.tier === 'tier1', 'one-file trivial task remains tier1');
67
67
  check(plan.strategy === 'direct-single', 'one-file trivial task selects direct-single');
68
68
  check(plan.strategySelection === 'selected', 'direct-single is a selected strategy');
69
+ check(plan.requiredInvariants.includes('visible-status-updates'), 'every selected workflow carries the user-visible status invariant');
69
70
  check(plan.workspace.required === false, 'direct-single does not require a workspace');
70
71
  check(plan.parallelism.allowed === false, 'direct-single does not parallelize');
71
72
  }
@@ -287,6 +288,8 @@ const kernelIterative = spawnSync(process.execPath, [kernelRouter, 'Fix this che
287
288
  });
288
289
  check(kernelIterative.stdout.includes('"strategy":"iterative-single"'), 'kernel consumes strategy from structured plan');
289
290
  check(kernelIterative.stdout.includes('loop-awareness:'), 'kernel prints dynamic plan guidance');
291
+ check(kernelIterative.stdout.includes('visible-status-updates:'), 'kernel prints the user-visible status invariant');
292
+ check(kernelIterative.stdout.includes('USER-VISIBLE HARNESS STATUS CONTRACT (MUST)'), 'kernel prints the canonical mandatory user-visible status contract');
290
293
  check(kernelIterative.stdout.includes(' - tdd'), 'kernel prints advisory skills separately');
291
294
 
292
295
  for (const schemaPath of [
@@ -13,7 +13,8 @@ The minimal kernel establishes:
13
13
  - applicability evaluation for every suggested skill before omission,
14
14
  - objective evidence before completion,
15
15
  - bounded re-plan/recovery after repeated failure,
16
- - explicit warnings/degraded/escape evidence instead of silent workflow deletion.
16
+ - explicit warnings/degraded/escape evidence instead of silent workflow deletion;
17
+ - one mandatory user-visible Harness Status protocol for non-trivial work, independent of execution topology.
17
18
 
18
19
  > **Guidance-first workflow; flexible reasoning/implementation and execution.**
19
20
  >
@@ -54,6 +55,22 @@ flowchart TD
54
55
 
55
56
  The router does not tell the model *how* to solve each stage. It decides what lifecycle shape is required. `direct-single`, `iterative-single`, `fable-staged`, `fable-parallel`, and `fable-multi-agent-workspace` remain deliberately small, non-overlapping topology choices.
56
57
 
58
+ ### User-visible status protocol
59
+
60
+ Non-trivial work MUST expose one stable progress shape to the user:
61
+
62
+ ```text
63
+ Harness Status
64
+ - Current: <what is being done now>
65
+ - Read/Evidence: <important files/sources/evidence read or confirmed>
66
+ - Next: <next intended action>
67
+ - Blocked/Risk: <only when materially applicable>
68
+ ```
69
+
70
+ The agent emits it before substantive execution, after major phases, on material direction changes, at meaningful long-running phase boundaries, and before final completion. The router checkpoint feeds this status but is not a second user-facing template.
71
+
72
+ This is a semantic contract, not another cognitive lock. Hook-capable hosts may observe or remind about compliance; instruction-only hosts still receive the MUST contract without pretending they can mechanically enforce it.
73
+
57
74
  ### Skill applicability vs. topology execution
58
75
 
59
76
  Router suggestions remain useful domain/workflow knowledge, not a universal sequence. Before omission, the agent reads the complete `SKILL.md` entry and evaluates `USE FOR`, `DO NOT USE FOR`, workflow/basic flow, and hard rules. Name/description/router-summary or “routine task” is insufficient evidence.
package/docs/routing.md CHANGED
@@ -19,6 +19,7 @@ For software/project work, Harness establishes routing context and lightweight r
19
19
  3. **Re-plan after repeated failure** — after three same-signature failures, stop micro-retrying and use a fresh diagnosis / `zoom-out`.
20
20
  4. **Evaluate before omission** — read every suggested skill's complete `SKILL.md` entry before deciding applicability.
21
21
  5. **Review selected workflow** — use it as planning guidance and surface unresolved evidence before claiming completion.
22
+ 6. **Surface status** — non-trivial work MUST keep the user informed through the single Harness Status format at required phase boundaries.
22
23
 
23
24
  The model owns tools, implementation technique, reasoning, and decomposition details inside those rails.
24
25
 
@@ -44,6 +45,22 @@ npx github:dyphn1/Harness-everything next "<prompt>"
44
45
 
45
46
  On a host where `UserPromptSubmit` is wired, reuse that hook output instead of running it twice.
46
47
 
48
+ ## User-visible status contract
49
+
50
+ For non-trivial software/project work, the user-facing progress protocol is a semantic **MUST** and is identical across execution topologies:
51
+
52
+ ```text
53
+ Harness Status
54
+ - Current: <what is being done now>
55
+ - Read/Evidence: <important files/sources/evidence read or confirmed>
56
+ - Next: <next intended action>
57
+ - Blocked/Risk: <only when materially applicable>
58
+ ```
59
+
60
+ Emit it before substantive execution, after a major phase, when direction materially changes, at meaningful long-running phase boundaries, and before final completion. The final response may fold the last status into its completion summary. The routing checkpoint is source state for this protocol, not a second user-facing progress template.
61
+
62
+ This MUST is semantic rather than a hard runtime lock: hosts may observe/remind with different strength, but lack of a blocking hook does not downgrade the contract to optional advice.
63
+
47
64
  ## Suggested skills vs. selected workflow
48
65
 
49
66
  These are intentionally different concepts.
@@ -127,10 +144,12 @@ Direct/iterative verification milestones are checked, while semantic check quali
127
144
 
128
145
  Workflow guidance is intentionally non-blocking across hosts. Keep that separate from Rule-of-3 and explicit permission enforcement.
129
146
 
130
- - **contract:** what the agent is required to do;
131
- - **mechanism:** which transitions a packaged hook/plugin can block or observe;
147
+ - **semantic contract:** what the agent MUST do, including the unified Harness Status where applicable;
148
+ - **mechanism:** which transitions a packaged hook/plugin can block, observe, or remind about;
132
149
  - **live evidence:** whether a real host actually loaded/fired that mechanism.
133
150
 
151
+ Semantic MUST and mechanical blocking are intentionally separate. A required communication or engineering obligation does not need a persistent runtime lock to remain mandatory.
152
+
134
153
  Instruction-only integrations receive the same workflow contract as guidance, but must not be labeled hard-enforced. Kernel emission alone does not prove model compliance. #82 owns host-specific retained evidence.
135
154
 
136
155
  Do not infer cross-host parity from shared runtime code or passing package tests.
@@ -8,12 +8,27 @@ The runtime follows **minimal rails, maximum freedom**:
8
8
 
9
9
  - routing selects a useful topology and suggested skills;
10
10
  - workflow state records useful evidence and unresolved obligations;
11
+ - the agent MUST use the single user-visible Harness Status format at required phase boundaries for non-trivial work;
11
12
  - verification hooks remind when evidence is missing;
12
13
  - worktree/isolation checks warn when a safer execution shape is available;
13
14
  - iteration, revision, replan, and worker counts are planning hints only.
14
15
 
15
16
  None of those cognitive workflow conditions should trap a session or require a reset command.
16
17
 
18
+ A semantic MUST is not the same thing as a hard runtime lock. User-visible status, routing/applicability obligations, and verification-before-claim can remain mandatory agent contracts while host hooks observe or remind on a best-effort basis. Do not downgrade a semantic obligation to optional advice merely because the host cannot block it.
19
+
20
+ The unified status shape is:
21
+
22
+ ```text
23
+ Harness Status
24
+ - Current: <what is being done now>
25
+ - Read/Evidence: <important files/sources/evidence read or confirmed>
26
+ - Next: <next intended action>
27
+ - Blocked/Risk: <only when materially applicable>
28
+ ```
29
+
30
+ Emit it before substantive execution, after major phases, on material direction changes, at meaningful long-running phase boundaries, and before final completion.
31
+
17
32
  The two intentionally separate hard boundaries are:
18
33
 
19
34
  1. **Rule of 3** — the third matching failure pauses mutation until a zoom-out reflection is written;
@@ -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.6
7
+ version: 0.18.0
8
8
  ---
9
9
 
10
10
  # Harness Everything
@@ -23,11 +23,12 @@ Kernel routing entry.
23
23
  2. **Verify before claim** — seek objective evidence before saying work is done.
24
24
  3. **Zoom out on repetition** — after 3 same-signature failures, use `zoom-out`.
25
25
  4. **Evaluate before omission** — read each suggested skill's `SKILL.md` before deciding applicability.
26
- 5. **Keep agency** — workflow state and numeric limits guide; they do not hard-stop execution.
26
+ 5. **Surface status** — non-trivial work MUST use one `Harness Status`: `Current`, `Read/Evidence`, `Next`, optional `Blocked/Risk`, at major phase/direction boundaries.
27
+ 6. **Keep agency** — workflow state and numeric limits guide; they do not hard-stop execution.
27
28
 
28
29
  ## Workflow
29
30
  1. Reuse kernel output, or run `node "<this-skill-dir>/scripts/kernel-router.js" "<prompt summary>"`.
30
- 2. Surface the **Harness Routing Checkpoint**.
31
+ 2. Use the **Harness Routing Checkpoint** to populate the first Harness Status; it is not a second progress format.
31
32
  3. Read each suggested `SKILL.md`; evaluate `USE FOR`, `DO NOT USE FOR`, workflow/basic flow, and hard rules.
32
33
  4. Use the selected topology as planning guidance. Choose, combine, reorder, or skip steps when evidence supports doing so.
33
34
  5. Prefer worktree isolation for broad/Tier-3 mutation and objective verification before completion.
@@ -44,6 +44,7 @@ The kernel protects lifecycle obligations without micromanaging model reasoning.
44
44
  3. **Re-plan on repetition** — after three same-signature failures, stop micro-retrying and use a fresh diagnosis / `zoom-out`.
45
45
  4. **Evaluate before omission** — when the router suggests a skill, read its complete `SKILL.md` entry/basic flow before deciding applicability.
46
46
  5. **Review selected workflow** — use the topology as planning guidance and keep any skipped step evidence-based.
47
+ 6. **Surface status** — non-trivial software/project work MUST use the single Harness Status format at required phase boundaries.
47
48
 
48
49
  The model remains free to choose tools, implementation technique, decomposition details, and reasoning inside the workflow.
49
50
 
@@ -148,9 +149,25 @@ On Claude and the local OpenAI package, supported hooks observe workflow/worktre
148
149
 
149
150
  Never turn mechanism/package evidence into a cross-host live-enforcement claim. #82 owns host-specific retained evidence.
150
151
 
151
- ## 6. Routing Checkpoint
152
+ ## 6. User-visible status contract
152
153
 
153
- For software/project work, surface this state before or with the first progress update:
154
+ For non-trivial software/project work, user-facing progress **MUST** use one stable shape across direct, iterative, Fable, and multi-agent execution:
155
+
156
+ ```text
157
+ Harness Status
158
+ - Current: <what is being done now>
159
+ - Read/Evidence: <important files/sources/evidence read or confirmed>
160
+ - Next: <next intended action>
161
+ - Blocked/Risk: <only when materially applicable>
162
+ ```
163
+
164
+ Emit it before substantive execution, after a major phase completes, when the plan/assumption/direction materially changes, at meaningful phase boundaries during long-running work, and before final completion. The final response may merge the last status naturally.
165
+
166
+ This is a semantic communication MUST. It does **not** create a runtime lock, counter, reset requirement, or permission boundary. The routing checkpoint below is source state for this format, not a second competing progress template.
167
+
168
+ ## 7. Routing Checkpoint
169
+
170
+ For software/project work, consume this runtime state when producing the first Harness Status:
154
171
 
155
172
  ```markdown
156
173
  ## 🚦 Harness Routing Checkpoint
@@ -163,9 +180,9 @@ For software/project work, surface this state before or with the first progress
163
180
  - Escape: <none | reason + uncovered scope + evidence>
164
181
  ```
165
182
 
166
- The checkpoint is state, not a universal response template. The key distinction is: **skill suggestions are evaluated for applicability; a selected topology guides execution but does not trap it.**
183
+ The checkpoint is runtime/source state, not a competing user-facing template. Render user progress through the single Harness Status contract above. The key distinction is: **skill suggestions are evaluated for applicability; a selected topology guides execution but does not trap it.**
167
184
 
168
- ## 7. Self-Healing and Dynamic Skills
185
+ ## 8. Self-Healing and Dynamic Skills
169
186
 
170
187
  Self-heal, generated-skill discovery, knowledge-guide matching, and fact-audit behavior remain part of the runtime. Dynamic recommendations still require applicability evaluation.
171
188