harness-everything 0.31.2 → 0.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +30 -0
- package/bin/cli.js +1 -0
- package/ci/lib/isolated-test-process.js +30 -0
- package/ci/mechanism-2al-codex-hooks-compat.test.js +14 -14
- package/ci/mechanism-2ao-plugin-sync.test.js +19 -2
- package/ci/mechanism-2at-fable-execution-phases.test.js +46 -0
- package/ci/mechanism-2au-codex-runtime-safety.test.js +340 -0
- package/ci/mechanism-2av-test-home-isolation.test.js +48 -0
- package/ci/mechanism-2az-step-type-registry.test.js +837 -0
- package/ci/mechanism-2ba-step-type-docs.test.js +166 -0
- package/ci/mechanism-test.js +2 -2
- package/docs/platform-capabilities.md +4 -0
- package/docs/platform-compatibility.json +1 -1
- package/fable-mode/SKILL.md +1 -1
- package/fable-mode/execution-guardrails/SKILL.md +1 -1
- package/fable-mode/fable-haiku/SKILL.md +1 -1
- package/fable-mode/fable-opus/SKILL.md +1 -1
- package/fable-mode/fable-sonnet/SKILL.md +1 -1
- package/fable-mode/references/execution-phases.md +93 -25
- package/harness-everything/SKILL.md +1 -1
- package/harness-everything/references/router-workflow-plan.md +18 -0
- package/harness-everything/scripts/kernel-router.js +37 -5
- package/hooks/scripts/codex-user-prompt.js +5 -2
- package/hooks/scripts/lib/step-types.json +37 -0
- package/hooks/scripts/lib/workflow-obligations.js +117 -14
- package/hooks/scripts/workflow-disposition.js +16 -9
- package/hooks/scripts/workflow-stop-gate.js +31 -8
- package/opencode-plugin/plugin.json +1 -1
- package/package.json +2 -2
- package/plugins/harness-everything/.codex-plugin/plugin.json +1 -1
- package/plugins/harness-everything/hooks/scripts/codex-user-prompt.js +5 -2
- package/plugins/harness-everything/hooks/scripts/lib/step-types.json +37 -0
- package/plugins/harness-everything/hooks/scripts/lib/workflow-obligations.js +117 -14
- package/plugins/harness-everything/hooks/scripts/workflow-disposition.js +16 -9
- package/plugins/harness-everything/hooks/scripts/workflow-stop-gate.js +31 -8
- package/plugins/harness-everything/plugin.json +1 -1
- package/plugins/harness-everything/skills/fable-mode/SKILL.md +1 -1
- package/plugins/harness-everything/skills/fable-mode/execution-guardrails/SKILL.md +1 -1
- package/plugins/harness-everything/skills/fable-mode/fable-haiku/SKILL.md +1 -1
- package/plugins/harness-everything/skills/fable-mode/fable-opus/SKILL.md +1 -1
- package/plugins/harness-everything/skills/fable-mode/fable-sonnet/SKILL.md +1 -1
- package/plugins/harness-everything/skills/fable-mode/references/execution-phases.md +93 -25
- package/plugins/harness-everything/skills/harness-everything/SKILL.md +1 -1
- package/plugins/harness-everything/skills/harness-everything/references/router-workflow-plan.md +18 -0
- package/plugins/harness-everything/skills/harness-everything/scripts/kernel-router.js +37 -5
- package/plugins/harness-everything/skills/self-evolve/SKILL.md +1 -1
- package/plugins/harness-everything/skills/self-evolve/scripts/self-regression.js +8 -6
- package/sbom.cdx.json +7 -7
- package/scripts/codex-hooks-compat.js +265 -25
- package/self-evolve/SKILL.md +1 -1
- package/self-evolve/scripts/self-regression.js +8 -6
|
@@ -3,35 +3,58 @@
|
|
|
3
3
|
const path = require('path');
|
|
4
4
|
const { readJson } = require('./lib/fable-contracts');
|
|
5
5
|
const { loadWorkflow, saveWorkflow, matchingRun, unresolvedStages, readHookInput } = require('./lib/workflow-runtime');
|
|
6
|
-
|
|
6
|
+
|
|
7
|
+
const REGISTRY_UNAVAILABLE = 'step-type-registry-unavailable';
|
|
8
|
+
const STEP_TYPE_REGISTRY_UNAVAILABLE = 'STEP_TYPE_REGISTRY_UNAVAILABLE';
|
|
7
9
|
|
|
8
10
|
function warn(message) { console.error('[Workflow Reminder] ' + message); }
|
|
9
11
|
|
|
10
12
|
function decide(payload) {
|
|
11
13
|
if (!payload) return;
|
|
12
14
|
try {
|
|
15
|
+
const { planningUnresolved, unresolvedObligations } = require('./lib/workflow-obligations');
|
|
13
16
|
const context = loadWorkflow(payload);
|
|
14
17
|
const { workflow, sessionDir } = context;
|
|
15
18
|
if (!workflow || workflow.state === 'deferred') return;
|
|
16
19
|
const handoff = readJson(path.join(sessionDir, 'handoff-state.json'));
|
|
17
|
-
|
|
20
|
+
const unresolved = [];
|
|
21
|
+
const diagnostics = [];
|
|
22
|
+
let requiredFault = false;
|
|
23
|
+
|
|
24
|
+
// Only a validation that actually reads the registry can fail here. It records the
|
|
25
|
+
// semantic diagnostic and the unresolved token itself; other checks keep running.
|
|
26
|
+
const required = check => {
|
|
27
|
+
try {
|
|
28
|
+
unresolved.push(...check());
|
|
29
|
+
} catch (error) {
|
|
30
|
+
if (error.code !== STEP_TYPE_REGISTRY_UNAVAILABLE) throw error;
|
|
31
|
+
diagnostics.push(error.message);
|
|
32
|
+
unresolved.push(REGISTRY_UNAVAILABLE);
|
|
33
|
+
requiredFault = true;
|
|
34
|
+
}
|
|
35
|
+
};
|
|
18
36
|
|
|
37
|
+
required(() => planningUnresolved(context));
|
|
19
38
|
if (String(workflow.strategy || '').startsWith('fable-')) {
|
|
20
39
|
const match = matchingRun(context);
|
|
21
40
|
unresolved.push(...(match ? unresolvedStages(match, workflow, handoff?.lastEditAt || 0) : ['correlated-run-missing']));
|
|
22
41
|
} else {
|
|
23
|
-
|
|
42
|
+
required(() => unresolvedObligations(context));
|
|
24
43
|
const lastEdit = Math.max(workflow.lastMutationAt || 0, handoff?.lastEditAt || 0);
|
|
25
44
|
if (lastEdit && (handoff?.lastVerifyAt || 0) < lastEdit) unresolved.push('verification-after-edit-missing');
|
|
26
45
|
}
|
|
27
46
|
|
|
28
|
-
|
|
47
|
+
const pending = [...new Set(unresolved)];
|
|
29
48
|
const wasBlocked = workflow.state === 'blocked';
|
|
30
49
|
if (wasBlocked) warn('Workflow is marked BLOCKED; report or revisit the recorded blocker, but Harness will not trap the session.');
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
50
|
+
[...new Set(diagnostics)].forEach(message => warn(message));
|
|
51
|
+
if (pending.length) {
|
|
52
|
+
// A failed required validation leaves the workflow file as recorded; it is never marked satisfied.
|
|
53
|
+
if (!requiredFault) {
|
|
54
|
+
workflow.unresolved = pending;
|
|
55
|
+
saveWorkflow(context);
|
|
56
|
+
}
|
|
57
|
+
warn('Unresolved workflow evidence: ' + pending.join(', ') + '. Resolve/verify before claiming completion.');
|
|
35
58
|
return;
|
|
36
59
|
}
|
|
37
60
|
if (wasBlocked) return;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
|
|
3
3
|
"name": "harness-everything",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.32.0",
|
|
5
5
|
"description": "Invariant-first engineering harness for routing, verification, and failure recovery while preserving agent autonomy.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Miya Daniel",
|
|
@@ -2,37 +2,105 @@
|
|
|
2
2
|
|
|
3
3
|
```mermaid
|
|
4
4
|
flowchart TD
|
|
5
|
-
Start[Qualifying Tier 3 task] --> Discover[Discover
|
|
6
|
-
Discover -->
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
Review --> Done[Record result or
|
|
5
|
+
Start[Qualifying Tier 3 task] --> Discover[Discover runtime and authorized scope]
|
|
6
|
+
Discover --> Profile[Resolve behavior profile and runtime choice]
|
|
7
|
+
Profile --> Plan[Write dependency-aware stage map and checks]
|
|
8
|
+
Plan --> Register[Write workflow-stages.json in session state]
|
|
9
|
+
Register --> Execute[Start workflow-disposition and execute ready stages]
|
|
10
|
+
Execute --> Check[Run exact check and record correlated evidence]
|
|
11
|
+
Check --> Review[Cold-review when the selected plan requires it]
|
|
12
|
+
Review --> Done[Record result or blocker]
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
## Discovery and planning
|
|
16
16
|
|
|
17
|
-
Read
|
|
18
|
-
authorized write scope
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
Read relevant files and sources before producing an artifact. Record the
|
|
18
|
+
authorized write scope. Give each stage an objective, dependencies, write set,
|
|
19
|
+
expected output, exact check command, and pass condition. Required and optional
|
|
20
|
+
bindings belong on the stage that needs them. Replan counts are advisory; after
|
|
21
|
+
three same-signature failures, use Rule-of-3 `zoom-out`.
|
|
21
22
|
|
|
22
|
-
##
|
|
23
|
+
## Profiles and delegation
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
25
|
+
Resolve a requested behavior profile with Fable's profile selector and record
|
|
26
|
+
it separately from the runtime choice. `fable-orchestrator`,
|
|
27
|
+
`fable-worker-sonnet`, and `fable-worker-haiku` name coordination,
|
|
28
|
+
reasoning/synthesis, and mechanical-work roles. These are behavior-profile
|
|
29
|
+
aliases; they do not switch the runtime model. Preserve an explicit user or
|
|
30
|
+
host runtime choice. Workers do not spawn workers. If a named worker is
|
|
31
|
+
unavailable, use a declared inline fallback or report the gap.
|
|
29
32
|
|
|
30
|
-
##
|
|
33
|
+
## Active workflow
|
|
34
|
+
|
|
35
|
+
For an active mandatory workflow, use the router-displayed session path for
|
|
36
|
+
`workflow-stages.json` and the router-displayed `workflow-disposition.js`
|
|
37
|
+
controller. Do not register active stages in a repository-local contracts
|
|
38
|
+
directory. Every required stage needs `dependsOn`, `writeSet`, `checkCommand`,
|
|
39
|
+
and `passCondition`; an independent plan also needs a read-only `fable-verifier`
|
|
40
|
+
stage that depends on all implementation stages.
|
|
41
|
+
|
|
42
|
+
Start the selected run with the controller path and session id from the router:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
node "<workflow-disposition.js path from the router>" start --session-id "<session-id>"
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The controller creates correlated run-scoped contracts. Load only bindings on
|
|
49
|
+
dependency-ready stages. Record each disposition with evidence:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
node "<workflow-disposition.js path from the router>" stage-binding \
|
|
53
|
+
--session-id "<session-id>" --stage-id "<stage-id>" \
|
|
54
|
+
--binding-id "<binding-id>" --disposition loaded \
|
|
55
|
+
--evidence "Read the resolved required reference for this stage."
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Run the exact `checkCommand`; the post-tool `contract-test.js` records the
|
|
59
|
+
session, run, stage, worker identity, numeric exit code, and check evidence. If
|
|
60
|
+
bindings are unresolved, resolve them and rerun the exact check before passing
|
|
61
|
+
the stage. Keep results under the run's `contracts/<stageId>.json` and
|
|
62
|
+
`evidence/<stageId>.json` records. Stage checks, required bindings, and selected
|
|
63
|
+
independent verification remain semantic MUSTs. The controller and lifecycle
|
|
64
|
+
hooks are reminder-only: unresolved evidence stays visible without locking
|
|
65
|
+
ordinary tools or Stop. See [`../CONTRACT-FORMAT.md`](../CONTRACT-FORMAT.md) for
|
|
66
|
+
the schema and correlation rules.
|
|
67
|
+
|
|
68
|
+
## Blocked recovery
|
|
31
69
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
70
|
+
If `start` is called while the workflow is running, it exits 2 with
|
|
71
|
+
`workflow already running; record a blocker before replanning`. From that
|
|
72
|
+
running state, record evidence with `block`:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
node "<workflow-disposition.js path from the router>" block \
|
|
76
|
+
--session-id "<session-id>" \
|
|
77
|
+
--evidence "The current stage map needs a bounded recovery update."
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Update the same session's `workflow-stages.json`, retaining the approved
|
|
81
|
+
requirements, workflow selection, dependencies, and required bindings. Then
|
|
82
|
+
start the revised stage map:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
node "<workflow-disposition.js path from the router>" start --session-id "<session-id>"
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
This starts a new run and clears the recorded block reason. If the session is
|
|
89
|
+
already `blocked`, update its stage map and run `start` directly. Do not call
|
|
90
|
+
`plan` from `blocked`: planning is accepted only while the workflow is pending
|
|
91
|
+
or active. When an explicitly authorized scope change requires new requirement
|
|
92
|
+
composition, route a new session instead of replacing approved requirements.
|
|
93
|
+
|
|
94
|
+
## Legacy/manual fallback
|
|
95
|
+
|
|
96
|
+
The path `.claude/harness-everything/state/contracts/<stage>.json` belongs only
|
|
97
|
+
to an explicitly selected legacy/manual workflow without an active mandatory
|
|
98
|
+
run. It does not register stages or correlated evidence for the current
|
|
99
|
+
workflow controller. Do not use it for an active Fable workflow.
|
|
100
|
+
|
|
101
|
+
## Verification and handoff
|
|
37
102
|
|
|
38
|
-
|
|
103
|
+
Run each named check and review scope-guard evidence before delivery. When the
|
|
104
|
+
selected plan requires independent verification, the verifier is read-only and
|
|
105
|
+
uses a distinct worker identity after all other stages pass. Record a blocker
|
|
106
|
+
or an evidence-backed result; do not discard unresolved requirements.
|
package/plugins/harness-everything/skills/harness-everything/references/router-workflow-plan.md
CHANGED
|
@@ -118,6 +118,24 @@ Examples:
|
|
|
118
118
|
|
|
119
119
|
There is no universal `TODO → TDD → verification` pipeline.
|
|
120
120
|
|
|
121
|
+
## Step types
|
|
122
|
+
|
|
123
|
+
The allowed step types are the entries of `hooks/scripts/lib/step-types.json`. The list below is rendered from that registry and checked against it by `ci/mechanism-2ba-step-type-docs.test.js`; examples elsewhere may name a subset.
|
|
124
|
+
|
|
125
|
+
<!-- step-types:start -->
|
|
126
|
+
- `behavior-change` — required bindings: `tdd` — forbidden bindings: none
|
|
127
|
+
- `commit` — required bindings: `git-commit` — forbidden bindings: none
|
|
128
|
+
- `doc-change` — required bindings: none — forbidden bindings: none
|
|
129
|
+
- `review` — required bindings: none — forbidden bindings: `tdd`
|
|
130
|
+
- `verification` — required bindings: `verification-loop` — forbidden bindings: none
|
|
131
|
+
<!-- step-types:end -->
|
|
132
|
+
|
|
133
|
+
`doc-change` is declared-only: a plan author chooses it explicitly, and router classification, keyword routing and System One never infer or insert it. It has no default bindings, and an explicitly declared `tdd` binding stays legal. Mixed documentation and code work is written as ordered `doc-change` and `behavior-change` steps, and one shared verification step may verify both.
|
|
134
|
+
|
|
135
|
+
Old runtimes reject a persisted non-Fable `doc-change` plan visibly at the controller and Stop boundaries (`planning:steps-invalid`). The old retained router does not show that rejection: it shows no active step. Persisted bytes are not renamed or reset. Inert Fable planning metadata is not rejected by old runtimes, because step bindings are disabled there.
|
|
136
|
+
|
|
137
|
+
Registry revisions: binding defaults and required/forbidden binding policy are materialized when a plan is recorded and are not reapplied on ordinary load. Existing typed plans must still reference currently registered step types; removing a type can invalidate a plan rather than migrate or waive its stored bindings. A policy fingerprint or migration path is future work and is not implemented today.
|
|
138
|
+
|
|
121
139
|
## Binding and disclosure rule
|
|
122
140
|
|
|
123
141
|
Each ordered requirement or Fable stage may declare `requiredBindings` and `optionalBindings` by stable id and concrete repository-relative path. Only the active requirement or dependency-ready stage exposes its paths. Required bindings must resolve before that step/stage passes; unknown required bindings remain visible and unresolved. Future-step paths and keyword-matched documents are never preloaded.
|
|
@@ -33,6 +33,14 @@ function issueMemoryCapability(workflow) {
|
|
|
33
33
|
return token;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
function needsStepTypeRegistry(plan) {
|
|
37
|
+
return Boolean(
|
|
38
|
+
plan && plan.strategySelection === 'selected' &&
|
|
39
|
+
['tier2', 'tier3'].includes(plan.tier) && plan.strategy &&
|
|
40
|
+
!String(plan.strategy).startsWith('fable-')
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
36
44
|
// Host-generated background-task notifications arrive as UserPromptSubmit
|
|
37
45
|
// hook payloads but are not user input (#168). Routing them like prompts
|
|
38
46
|
// replaces the workflow contract mid-turn (e.g. deferred -> a new Tier-2).
|
|
@@ -44,11 +52,28 @@ function isHostNotificationPrompt(prompt) {
|
|
|
44
52
|
return /^<task-notification[\s>][\s\S]*<\/task-notification>\s*$/i.test(text);
|
|
45
53
|
}
|
|
46
54
|
|
|
55
|
+
function stepTypeIdsFor(hooksRoot) {
|
|
56
|
+
try {
|
|
57
|
+
return require(path.join(hooksRoot, 'lib/workflow-obligations')).stepTypeIds();
|
|
58
|
+
} catch {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
47
63
|
function persistWorkflow(contract, payload, prompt) {
|
|
48
64
|
const plan = contract && contract.workflowPlan;
|
|
49
65
|
if (!payload || !(payload.session_id || payload.sessionId)) return null;
|
|
50
66
|
const { runtime, hooksRoot } = loadRuntime();
|
|
51
67
|
const context = runtime.loadWorkflow(payload);
|
|
68
|
+
const hasRetainedWorkflow = Boolean(context.workflow && runtime.OPEN_STATES.has(context.workflow.state));
|
|
69
|
+
const activePlan = hasRetainedWorkflow ? context.workflow.workflowPlan : plan;
|
|
70
|
+
if (needsStepTypeRegistry(activePlan)) {
|
|
71
|
+
try { require(path.join(hooksRoot, 'lib/workflow-obligations')).loadStepTypeRegistry(); }
|
|
72
|
+
catch (error) {
|
|
73
|
+
if (hasRetainedWorkflow) return { ...context, hooksRoot, retained: true, registryError: error };
|
|
74
|
+
throw error;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
52
77
|
const { writeCurrentSession } = require(path.join(hooksRoot, 'lib/harness-state'));
|
|
53
78
|
writeCurrentSession(context.root, context.sessionId);
|
|
54
79
|
if (isHostNotificationPrompt(prompt)) {
|
|
@@ -121,8 +146,8 @@ function activeExecutionFor(persisted, plan) {
|
|
|
121
146
|
const obligations = require(path.join(persisted.hooksRoot, 'lib/workflow-obligations'));
|
|
122
147
|
const loaded = obligations.loadObligationSet(persisted, plan);
|
|
123
148
|
return { activeStep: loaded.set ? obligations.activeStepSnapshot(loaded.set) : null };
|
|
124
|
-
} catch (
|
|
125
|
-
return
|
|
149
|
+
} catch (error) {
|
|
150
|
+
return { error: error && error.message ? error.message : String(error) };
|
|
126
151
|
}
|
|
127
152
|
}
|
|
128
153
|
|
|
@@ -163,10 +188,15 @@ function run(raw) {
|
|
|
163
188
|
if (persisted?.retained && persisted.workflow) {
|
|
164
189
|
if (persisted.hostNotification) console.log('\n=> Host notification: routing unchanged; keeping the active execution contract.');
|
|
165
190
|
else console.log('\n=> Retaining unresolved workflow; showing its compact active contract.');
|
|
166
|
-
const activeExecution =
|
|
191
|
+
const activeExecution = persisted.registryError
|
|
192
|
+
? { error: persisted.registryError.message || String(persisted.registryError) }
|
|
193
|
+
: activeExecutionFor(persisted, plan) || {};
|
|
167
194
|
const activeStep = activeExecution.activeStep || null;
|
|
168
195
|
const activeStages = activeExecution.activeStages || [];
|
|
169
196
|
core.printRetainedWorkflow(plan, persisted.workflow, activeStep, activeStages);
|
|
197
|
+
if (activeExecution.error) {
|
|
198
|
+
console.log(' - [Workflow Reminder] Active-step context unavailable: ' + activeExecution.error);
|
|
199
|
+
}
|
|
170
200
|
if (activeStep) {
|
|
171
201
|
const controller = path.join(persisted.hooksRoot, 'workflow-disposition.js');
|
|
172
202
|
console.log(' - Resolve only bindings for this active step, then pass this step with evidence.');
|
|
@@ -205,8 +235,10 @@ function run(raw) {
|
|
|
205
235
|
if (plan.strategySelection === 'selected' && ['tier2', 'tier3'].includes(plan.tier)) {
|
|
206
236
|
console.log(' - Planning contract: ' + path.join(persisted.sessionDir, 'workflow-obligations.json'));
|
|
207
237
|
console.log(' - Requirements first: decompose intent into requirement fragments, then confirm the smallest sufficient workflow.');
|
|
208
|
-
|
|
209
|
-
console.log(' - Record
|
|
238
|
+
const stepTypeIds = stepTypeIdsFor(persisted.hooksRoot);
|
|
239
|
+
console.log(' - Record ordered step types' + (stepTypeIds ? ' (' + stepTypeIds.join(', ') + ')' : '') + ' and their bindings before execution.');
|
|
240
|
+
console.log(' - Replace <step-type-id> with a registered type you choose explicitly; mixed docs+code work uses separate doc-change and behavior-change steps; keep the verification step.');
|
|
241
|
+
console.log(' - Record plan: node "' + controller + '" plan --session-id "' + persisted.sessionId + '" --requirements-json "[{\\"id\\":\\"req-1\\",\\"stepType\\":\\"<step-type-id>\\",\\"summary\\":\\"...\\",\\"acceptance\\":\\"...\\"},{\\"id\\":\\"req-verify\\",\\"stepType\\":\\"verification\\",\\"summary\\":\\"...\\",\\"acceptance\\":\\"...\\"}]" --strategy "' + plan.strategy + '" --evidence "<why this workflow fits>"');
|
|
210
242
|
}
|
|
211
243
|
console.log(' - Enter selected workflow after planning: node "' + controller + '" start --session-id "' + persisted.sessionId + '"');
|
|
212
244
|
console.log(' - Escape one declared stage: node "' + controller + '" escape --session-id "' + persisted.sessionId + '" --stage-id "<id>" --reason-code workflow-uncovered-scope --scope "<uncovered scope>" --evidence "<evidence>"');
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
* their results must not be confused with a local tracker simulation.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
const { spawnSync } = require('child_process');
|
|
10
9
|
const path = require('path');
|
|
11
10
|
const fs = require('fs');
|
|
12
11
|
|
|
@@ -22,12 +21,15 @@ if (pkgName !== 'harness-everything') {
|
|
|
22
21
|
process.exit(0);
|
|
23
22
|
}
|
|
24
23
|
|
|
24
|
+
// This development-only helper is absent from installed skill packages.
|
|
25
|
+
const { spawnTestNode } = require('../../ci/lib/isolated-test-process');
|
|
26
|
+
|
|
25
27
|
console.log('=================================================');
|
|
26
28
|
console.log(' Harness OS - Self-Regression Test Suite ');
|
|
27
29
|
console.log('=================================================');
|
|
28
30
|
|
|
29
31
|
function runNode(label, script, args = [], options = {}) {
|
|
30
|
-
const result =
|
|
32
|
+
const result = spawnTestNode([script, ...args], {
|
|
31
33
|
cwd: projectRoot,
|
|
32
34
|
stdio: 'inherit',
|
|
33
35
|
...options,
|
|
@@ -54,7 +56,7 @@ function walkDir(dir) {
|
|
|
54
56
|
}
|
|
55
57
|
for (const folder of foldersToScan) walkDir(path.join(projectRoot, folder));
|
|
56
58
|
for (const file of jsFiles) {
|
|
57
|
-
const check =
|
|
59
|
+
const check = spawnTestNode(['--check', file]);
|
|
58
60
|
if (check.status !== 0) {
|
|
59
61
|
console.error(` FAIL syntax: ${path.relative(projectRoot, file)}`);
|
|
60
62
|
console.error(check.stderr.toString().trim());
|
|
@@ -65,7 +67,7 @@ console.log(` PASS syntax: ${jsFiles.length} JavaScript file(s)`);
|
|
|
65
67
|
|
|
66
68
|
console.log('\n[Phase 1b] CLI Command Smoke Test...');
|
|
67
69
|
const cliPath = path.join(projectRoot, 'bin', 'cli.js');
|
|
68
|
-
const nextCheck =
|
|
70
|
+
const nextCheck = spawnTestNode([cliPath, 'next', 'add a new login endpoint with tests'], { cwd: projectRoot });
|
|
69
71
|
if (nextCheck.status !== 0 || !nextCheck.stdout.toString().includes('RECOMMENDED TIER')) {
|
|
70
72
|
console.error(' FAIL `harness next` did not produce a routing recommendation.');
|
|
71
73
|
hasErrors = true;
|
|
@@ -73,7 +75,7 @@ if (nextCheck.status !== 0 || !nextCheck.stdout.toString().includes('RECOMMENDED
|
|
|
73
75
|
console.error(' FAIL `harness next` did not establish the invariant-first kernel contract.');
|
|
74
76
|
hasErrors = true;
|
|
75
77
|
} else console.log(' PASS `harness next` produced routing + invariant contract.');
|
|
76
|
-
const verifyCheck =
|
|
78
|
+
const verifyCheck = spawnTestNode([cliPath, 'verify'], {
|
|
77
79
|
cwd: projectRoot,
|
|
78
80
|
env: { ...process.env, HARNESS_SKIP_PROJECT_CHECKS: '1' },
|
|
79
81
|
});
|
|
@@ -105,7 +107,7 @@ runNode('behavioral case validation', path.join(projectRoot, 'behavioral-evals',
|
|
|
105
107
|
console.log('\n[Phase 3b] Fable Model Mode Contract Tests...');
|
|
106
108
|
const fableModeTestPath = path.join(projectRoot, 'ci', 'fable-mode-test.js');
|
|
107
109
|
if (fs.existsSync(fableModeTestPath)) {
|
|
108
|
-
const fableModeCheck =
|
|
110
|
+
const fableModeCheck = spawnTestNode([fableModeTestPath], { stdio: 'inherit', cwd: projectRoot });
|
|
109
111
|
if (fableModeCheck.status !== 0) {
|
|
110
112
|
console.error("\n ❌ Fable model mode contract suite failed!");
|
|
111
113
|
hasErrors = true;
|
package/sbom.cdx.json
CHANGED
|
@@ -2,23 +2,23 @@
|
|
|
2
2
|
"$schema": "https://cyclonedx.org/schema/bom-1.7.schema.json",
|
|
3
3
|
"bomFormat": "CycloneDX",
|
|
4
4
|
"specVersion": "1.7",
|
|
5
|
-
"serialNumber": "urn:uuid:
|
|
5
|
+
"serialNumber": "urn:uuid:10a4f889-cc27-520f-b5d1-1a628d22d914",
|
|
6
6
|
"version": 1,
|
|
7
7
|
"metadata": {
|
|
8
|
-
"timestamp": "2026-10-
|
|
8
|
+
"timestamp": "2026-10-17T13:06:24.281Z",
|
|
9
9
|
"tools": [
|
|
10
10
|
{
|
|
11
11
|
"vendor": "Harness Everything",
|
|
12
12
|
"name": "generate-sbom.js",
|
|
13
|
-
"version": "0.
|
|
13
|
+
"version": "0.32.0"
|
|
14
14
|
}
|
|
15
15
|
],
|
|
16
16
|
"component": {
|
|
17
17
|
"type": "application",
|
|
18
|
-
"bom-ref": "pkg:npm/harness-everything@0.
|
|
18
|
+
"bom-ref": "pkg:npm/harness-everything@0.32.0",
|
|
19
19
|
"name": "harness-everything",
|
|
20
|
-
"version": "0.
|
|
21
|
-
"purl": "pkg:npm/harness-everything@0.
|
|
20
|
+
"version": "0.32.0",
|
|
21
|
+
"purl": "pkg:npm/harness-everything@0.32.0"
|
|
22
22
|
}
|
|
23
23
|
},
|
|
24
24
|
"components": [
|
|
@@ -1999,7 +1999,7 @@
|
|
|
1999
1999
|
]
|
|
2000
2000
|
},
|
|
2001
2001
|
{
|
|
2002
|
-
"ref": "pkg:npm/harness-everything@0.
|
|
2002
|
+
"ref": "pkg:npm/harness-everything@0.32.0",
|
|
2003
2003
|
"dependsOn": [
|
|
2004
2004
|
"pkg:npm/%40commitlint/cli@19.8.1",
|
|
2005
2005
|
"pkg:npm/%40commitlint/config-conventional@19.8.1",
|