harness-everything 0.11.6 → 0.12.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 +45 -0
- package/README.md +7 -3
- package/behavioral-evals/README.md +37 -0
- package/behavioral-evals/cases/self-evolve-retrieval-recurrence.yaml +48 -0
- package/behavioral-evals/paired-benchmark.js +211 -5
- package/ci/contract-integrity.test.js +68 -2
- package/ci/mechanism-2a-rule-of-3.test.js +71 -0
- package/ci/mechanism-2ah-workflow-lifecycle.test.js +276 -0
- package/ci/mechanism-2c-state-persist.test.js +45 -2
- package/ci/mechanism-2t-issue-20.test.js +0 -8
- package/ci/mechanism-30-opencode-plugin-loadability.test.js +39 -7
- package/ci/mechanism-32-paired-benchmark.test.js +139 -0
- package/ci/openai-plugin-package.test.js +17 -0
- package/ci/self-evolve-loop.test.js +37 -2
- package/ci/telemetry.test.js +31 -1
- package/docs/architecture.md +17 -0
- package/docs/audit.md +52 -5
- package/docs/release-evidence.md +3 -0
- package/docs/workflow-runtime.md +13 -0
- package/docs/workflows/environment-detection.md +47 -37
- package/docs/workflows/eval-harness.md +45 -38
- package/docs/workflows/fable-discipline.md +45 -33
- package/docs/workflows/git-commit.md +53 -45
- package/docs/workflows/grill-me.md +36 -38
- package/docs/workflows/grill-with-docs.md +36 -46
- package/docs/workflows/harness-everything.md +59 -57
- package/docs/workflows/improve-codebase-architecture.md +36 -44
- package/docs/workflows/install-cognitive-os.md +36 -29
- package/docs/workflows/repo-docs.md +29 -40
- package/docs/workflows/rewrite-commits.md +40 -36
- package/docs/workflows/security-review.md +34 -53
- package/docs/workflows/skill-creator.md +39 -56
- package/docs/workflows/skill-style.md +35 -40
- package/docs/workflows/using-git-worktrees.md +40 -44
- package/docs/workflows/verification-loop.md +43 -48
- package/docs/workflows/verify-before-claim.md +37 -40
- package/docs/workflows/zoom-out.md +39 -51
- package/grill-with-docs/ADR-FORMAT.md +22 -0
- package/grill-with-docs/SKILL.md +1 -1
- package/harness-everything/SKILL.md +1 -1
- package/harness-everything/scripts/kernel-router.js +38 -10
- package/hooks/scripts/lib/learning-opportunity.js +22 -0
- package/hooks/scripts/lib/telemetry.js +40 -0
- package/hooks/scripts/lib/workflow-isolation.js +30 -1
- package/hooks/scripts/lib/workflow-runtime.js +18 -1
- package/hooks/scripts/rule-of-3-tracker.js +17 -9
- package/hooks/scripts/state-persist.js +19 -7
- package/hooks/scripts/workflow-disposition.js +19 -8
- package/hooks/scripts/workflow-gate.js +21 -4
- package/multi-agent-workspace/SKILL.md +1 -1
- package/multi-agent-workspace/scripts/index_memory.js +28 -0
- package/opencode-plugin/plugin.json +1 -1
- package/package.json +1 -1
- package/plugins/harness-everything/.codex-plugin/plugin.json +1 -1
- package/plugins/harness-everything/contract-integrity/scripts/audit.js +536 -0
- package/plugins/harness-everything/hooks/scripts/lib/learning-opportunity.js +22 -0
- package/plugins/harness-everything/hooks/scripts/lib/telemetry.js +40 -0
- package/plugins/harness-everything/hooks/scripts/lib/workflow-isolation.js +30 -1
- package/plugins/harness-everything/hooks/scripts/lib/workflow-runtime.js +18 -1
- package/plugins/harness-everything/hooks/scripts/rule-of-3-tracker.js +17 -9
- package/plugins/harness-everything/hooks/scripts/state-persist.js +19 -7
- package/plugins/harness-everything/hooks/scripts/workflow-disposition.js +19 -8
- package/plugins/harness-everything/hooks/scripts/workflow-gate.js +21 -4
- package/plugins/harness-everything/plugin.json +1 -1
- package/plugins/harness-everything/skills/grill-with-docs/ADR-FORMAT.md +22 -0
- package/plugins/harness-everything/skills/grill-with-docs/SKILL.md +1 -1
- package/plugins/harness-everything/skills/harness-everything/SKILL.md +1 -1
- package/plugins/harness-everything/skills/harness-everything/scripts/kernel-router.js +38 -10
- package/plugins/harness-everything/skills/multi-agent-workspace/SKILL.md +1 -1
- package/plugins/harness-everything/skills/multi-agent-workspace/scripts/index_memory.js +28 -0
- package/plugins/harness-everything/skills/self-evolve/SKILL.md +1 -1
- package/plugins/harness-everything/skills/self-evolve/scripts/lesson-candidate.js +52 -0
- package/plugins/harness-everything/skills/to-spec/SKILL.md +1 -1
- package/plugins/harness-everything/skills/to-spec/references/process.md +26 -0
- package/plugins/harness-everything/skills/to-spec/templates/cli-reference.md +14 -0
- package/plugins/harness-everything/skills/to-spec/templates/dev-doc.md +14 -0
- package/plugins/harness-everything/skills/to-spec/templates/feature-spec.md +14 -0
- package/plugins/harness-everything/skills/to-spec/templates/schema-doc.md +14 -0
- package/plugins/harness-everything/skills/to-tickets/SKILL.md +1 -1
- package/plugins/harness-everything/skills/to-tickets/references/publishing-and-templates.md +20 -1
- package/plugins/harness-everything/skills/verification-loop/SKILL.md +3 -2
- package/plugins/harness-everything/skills/verification-loop/references/verification-phases.md +25 -1
- package/plugins/harness-everything/skills/verification-loop/scripts/contract-integrity-audit.js +31 -0
- package/plugins/harness-everything/skills/verification-loop/templates/verification-report.template.md +3 -0
- package/scripts/sync-openai-plugin.js +12 -0
- package/self-evolve/SKILL.md +1 -1
- package/self-evolve/scripts/lesson-candidate.js +52 -0
- package/telemetry/schemas/event.schema.json +141 -22
- package/telemetry/scripts/report.js +42 -0
- package/to-spec/SKILL.md +1 -1
- package/to-spec/references/process.md +26 -0
- package/to-spec/templates/cli-reference.md +14 -0
- package/to-spec/templates/dev-doc.md +14 -0
- package/to-spec/templates/feature-spec.md +14 -0
- package/to-spec/templates/schema-doc.md +14 -0
- package/to-tickets/SKILL.md +1 -1
- package/to-tickets/references/publishing-and-templates.md +20 -1
- package/verification-loop/SKILL.md +3 -2
- package/verification-loop/references/verification-phases.md +25 -1
- package/verification-loop/scripts/contract-integrity-audit.js +31 -0
- package/verification-loop/templates/verification-report.template.md +3 -0
- package/docs/issue-20-rollup.md +0 -47
- package/docs/reviews/pr-142-issue-131.md +0 -89
|
@@ -6,8 +6,11 @@ const crypto = require('crypto');
|
|
|
6
6
|
const helper = require('./test-helper');
|
|
7
7
|
const {
|
|
8
8
|
mcnemarExactP,
|
|
9
|
+
pairContract,
|
|
9
10
|
prepareArmWorkspace,
|
|
11
|
+
retrieveLesson,
|
|
10
12
|
summarizePairs,
|
|
13
|
+
validateLessonCase,
|
|
11
14
|
validatePairRecord,
|
|
12
15
|
validateRunConfig,
|
|
13
16
|
} = require('../behavioral-evals/paired-benchmark');
|
|
@@ -142,6 +145,142 @@ try {
|
|
|
142
145
|
fs.rmSync(pluginBaseline.ws, { recursive: true, force: true });
|
|
143
146
|
fs.rmSync(pluginTreatment.ws, { recursive: true, force: true });
|
|
144
147
|
|
|
148
|
+
const lessonCase = {
|
|
149
|
+
id: 'lesson-retrieval-shape',
|
|
150
|
+
discipline: 'verify-before-claim',
|
|
151
|
+
loaded_skills: ['verify-before-claim'],
|
|
152
|
+
prompt: 'npm test is failing for higher retry attempts. Fix it and verify.',
|
|
153
|
+
max_turns: 8,
|
|
154
|
+
fixture: { files: [{ path: 'probe.txt', content: 'baseline\n' }] },
|
|
155
|
+
expectations: [{ type: 'file_contains', path: 'probe.txt', value: 'baseline' }],
|
|
156
|
+
lesson: {
|
|
157
|
+
candidate_id: 'lesson-0123456789abcdef01234567',
|
|
158
|
+
rule: 'When retry delay tests fail at higher attempts, inspect exponential backoff before changing caps and verify with npm test.',
|
|
159
|
+
scope_task: 'retry delay exponential backoff higher attempts npm test',
|
|
160
|
+
query_task: 'retry delay exponential backoff higher attempts npm test',
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
helper.check(
|
|
164
|
+
'32. lesson-retrieval case requires a valid accepted-lesson fixture contract',
|
|
165
|
+
validateLessonCase(lessonCase).length === 0,
|
|
166
|
+
validateLessonCase(lessonCase).join('; '),
|
|
167
|
+
);
|
|
168
|
+
const lessonConfigProblems = validateRunConfig({
|
|
169
|
+
effect_type: 'lesson-retrieval', engine: 'claude', model: 'test/model',
|
|
170
|
+
min_effect_pp: 10, repeats: 1,
|
|
171
|
+
});
|
|
172
|
+
helper.check(
|
|
173
|
+
'32. lesson-retrieval is an explicit paired effect type rather than being disguised as skill-text',
|
|
174
|
+
lessonConfigProblems.length === 0,
|
|
175
|
+
lessonConfigProblems.join('; '),
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
const lessonBaselinePrepared = prepareArmWorkspace(lessonCase, 'lesson-retrieval', 'baseline', 'claude');
|
|
179
|
+
const lessonTreatmentPrepared = prepareArmWorkspace(lessonCase, 'lesson-retrieval', 'treatment', 'claude');
|
|
180
|
+
const lessonStateBaseline = helper.tempDir('.paired-lesson-state-baseline');
|
|
181
|
+
const lessonStateTreatment = helper.tempDir('.paired-lesson-state-treatment');
|
|
182
|
+
const baselineLesson = retrieveLesson(
|
|
183
|
+
lessonCase, lessonBaselinePrepared.memoryStore, lessonStateBaseline, false,
|
|
184
|
+
);
|
|
185
|
+
const treatmentLesson = retrieveLesson(
|
|
186
|
+
lessonCase, lessonTreatmentPrepared.memoryStore, lessonStateTreatment, true,
|
|
187
|
+
);
|
|
188
|
+
helper.check(
|
|
189
|
+
'32. lesson memory store stays outside both agent workspaces',
|
|
190
|
+
!lessonBaselinePrepared.memoryStore.startsWith(lessonBaselinePrepared.ws + path.sep) &&
|
|
191
|
+
!lessonTreatmentPrepared.memoryStore.startsWith(lessonTreatmentPrepared.ws + path.sep) &&
|
|
192
|
+
!fs.existsSync(path.join(lessonBaselinePrepared.ws, 'memories')) &&
|
|
193
|
+
!fs.existsSync(path.join(lessonTreatmentPrepared.ws, 'memories')),
|
|
194
|
+
JSON.stringify({ baseline: lessonBaselinePrepared, treatment: lessonTreatmentPrepared }),
|
|
195
|
+
);
|
|
196
|
+
helper.check(
|
|
197
|
+
'32. both arms execute the same scoped retrieval while only treatment receives the context',
|
|
198
|
+
baselineLesson.evidence.queried === true &&
|
|
199
|
+
treatmentLesson.evidence.queried === true &&
|
|
200
|
+
baselineLesson.evidence.exposed === false &&
|
|
201
|
+
treatmentLesson.evidence.exposed === true &&
|
|
202
|
+
baselineLesson.evidence.retrieval_set_sha256 === treatmentLesson.evidence.retrieval_set_sha256 &&
|
|
203
|
+
JSON.stringify(baselineLesson.evidence.candidate_ids) === JSON.stringify(treatmentLesson.evidence.candidate_ids) &&
|
|
204
|
+
baselineLesson.prompt === lessonCase.prompt &&
|
|
205
|
+
treatmentLesson.prompt.includes('Harness scoped memory context') &&
|
|
206
|
+
treatmentLesson.prompt.includes(lessonCase.lesson.candidate_id),
|
|
207
|
+
JSON.stringify({ baseline: baselineLesson.evidence, treatment: treatmentLesson.evidence }),
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
const lessonContract = pairContract(lessonCase, {
|
|
211
|
+
effect_type: 'lesson-retrieval',
|
|
212
|
+
engine: 'claude',
|
|
213
|
+
model: 'test/model',
|
|
214
|
+
});
|
|
215
|
+
const lessonPair = {
|
|
216
|
+
schema_version: 1,
|
|
217
|
+
id: lessonCase.id,
|
|
218
|
+
pair_id: 'lesson-pair',
|
|
219
|
+
effect_type: 'lesson-retrieval',
|
|
220
|
+
contract: lessonContract,
|
|
221
|
+
contract_sha256: hash(lessonContract),
|
|
222
|
+
arms: {
|
|
223
|
+
baseline: {
|
|
224
|
+
...arm('fail', true),
|
|
225
|
+
intervention: { skill_text: true, plugin_enforcement: false, lesson_retrieval: false },
|
|
226
|
+
loaded_skills: ['verify-before-claim'],
|
|
227
|
+
lesson_retrieval: baselineLesson.evidence,
|
|
228
|
+
},
|
|
229
|
+
treatment: {
|
|
230
|
+
...arm('pass', true),
|
|
231
|
+
intervention: { skill_text: true, plugin_enforcement: false, lesson_retrieval: true },
|
|
232
|
+
loaded_skills: ['verify-before-claim'],
|
|
233
|
+
lesson_retrieval: treatmentLesson.evidence,
|
|
234
|
+
},
|
|
235
|
+
},
|
|
236
|
+
};
|
|
237
|
+
helper.check(
|
|
238
|
+
'32. attributed lesson-retrieval pair is includable only with constant skill text and identical retrieval set',
|
|
239
|
+
validatePairRecord(lessonPair).included,
|
|
240
|
+
JSON.stringify(validatePairRecord(lessonPair)),
|
|
241
|
+
);
|
|
242
|
+
const lessonSetMismatch = JSON.parse(JSON.stringify(lessonPair));
|
|
243
|
+
lessonSetMismatch.pair_id = 'lesson-set-mismatch';
|
|
244
|
+
lessonSetMismatch.arms.treatment.lesson_retrieval.retrieval_set_sha256 = 'different';
|
|
245
|
+
helper.check(
|
|
246
|
+
'32. mismatched memory retrieval set excludes the pair instead of counting it as lesson effect',
|
|
247
|
+
!validatePairRecord(lessonSetMismatch).included &&
|
|
248
|
+
validatePairRecord(lessonSetMismatch).reason === 'lesson-retrieval-set-mismatch',
|
|
249
|
+
JSON.stringify(validatePairRecord(lessonSetMismatch)),
|
|
250
|
+
);
|
|
251
|
+
const lessonTrustMissing = JSON.parse(JSON.stringify(lessonPair));
|
|
252
|
+
lessonTrustMissing.pair_id = 'lesson-trust-missing';
|
|
253
|
+
lessonTrustMissing.arms.treatment.lesson_retrieval.trust_boundary = null;
|
|
254
|
+
helper.check(
|
|
255
|
+
'32. treatment without the untrusted-memory boundary is excluded from causal evidence',
|
|
256
|
+
!validatePairRecord(lessonTrustMissing).included &&
|
|
257
|
+
validatePairRecord(lessonTrustMissing).reason === 'lesson-trust-boundary-missing',
|
|
258
|
+
JSON.stringify(validatePairRecord(lessonTrustMissing)),
|
|
259
|
+
);
|
|
260
|
+
const lessonContextTamper = JSON.parse(JSON.stringify(lessonPair));
|
|
261
|
+
lessonContextTamper.pair_id = 'lesson-context-tamper';
|
|
262
|
+
lessonContextTamper.arms.treatment.lesson_retrieval.context_sha256 = 'tampered';
|
|
263
|
+
helper.check(
|
|
264
|
+
'32. changed lesson exposure text invalidates the predeclared pair contract',
|
|
265
|
+
!validatePairRecord(lessonContextTamper).included &&
|
|
266
|
+
validatePairRecord(lessonContextTamper).reason === 'lesson-context-hash-mismatch',
|
|
267
|
+
JSON.stringify(validatePairRecord(lessonContextTamper)),
|
|
268
|
+
);
|
|
269
|
+
|
|
270
|
+
for (const target of [
|
|
271
|
+
lessonBaselinePrepared.ws, lessonTreatmentPrepared.ws,
|
|
272
|
+
lessonBaselinePrepared.memoryStore, lessonTreatmentPrepared.memoryStore,
|
|
273
|
+
lessonStateBaseline, lessonStateTreatment,
|
|
274
|
+
]) fs.rmSync(target, { recursive: true, force: true });
|
|
275
|
+
|
|
276
|
+
const invalidLesson = JSON.parse(JSON.stringify(lessonCase));
|
|
277
|
+
invalidLesson.lesson.candidate_id = 'not-a-lesson-id';
|
|
278
|
+
helper.check(
|
|
279
|
+
'32. malformed lesson provenance is rejected before any live model call',
|
|
280
|
+
validateLessonCase(invalidLesson).some(problem => problem.includes('candidate_id')),
|
|
281
|
+
validateLessonCase(invalidLesson).join('; '),
|
|
282
|
+
);
|
|
283
|
+
|
|
145
284
|
const validSkillPair = skillPair('p1', 'fail', 'pass');
|
|
146
285
|
helper.check('32. a correctly isolated skill-text pair is includable', validatePairRecord(validSkillPair).included, JSON.stringify(validatePairRecord(validSkillPair)));
|
|
147
286
|
|
|
@@ -112,6 +112,23 @@ for (const entry of SOURCE_MANIFEST.skills) {
|
|
|
112
112
|
assertTreesEqual(source, path.join(PLUGIN, 'skills', name), name);
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
const packagedContractAudit = path.join(PLUGIN, 'contract-integrity', 'scripts', 'audit.js');
|
|
116
|
+
assert.ok(fs.existsSync(packagedContractAudit), 'OpenAI package must include shared contract-integrity runtime outside skills/');
|
|
117
|
+
const packagedAuditSource = fs.readFileSync(packagedContractAudit, 'utf8');
|
|
118
|
+
assert.match(packagedAuditSource, /skills\/tdd\/scripts\/quality-gate/, 'packaged contract audit must resolve #58 evaluator from packaged tdd skill');
|
|
119
|
+
assert.doesNotMatch(packagedAuditSource, /\.\.\/\.\.\/tdd\/scripts\/quality-gate/, 'packaged contract audit must not retain canonical repo-only TDD import');
|
|
120
|
+
const packagedAudit = require(packagedContractAudit);
|
|
121
|
+
assert.strictEqual(typeof packagedAudit.runCli, 'function', 'packaged contract audit runtime must load and export runCli');
|
|
122
|
+
|
|
123
|
+
const verificationContractWrapper = path.join(PLUGIN, 'skills', 'verification-loop', 'scripts', 'contract-integrity-audit.js');
|
|
124
|
+
assert.ok(fs.existsSync(verificationContractWrapper), 'verification-loop must package its contract audit wrapper');
|
|
125
|
+
const verificationWrapper = require(verificationContractWrapper);
|
|
126
|
+
assert.strictEqual(
|
|
127
|
+
verificationWrapper.resolveAuditRuntime(),
|
|
128
|
+
packagedContractAudit,
|
|
129
|
+
'packaged verification-loop wrapper must resolve the plugin-root contract audit runtime'
|
|
130
|
+
);
|
|
131
|
+
|
|
115
132
|
const marketplace = JSON.parse(fs.readFileSync(path.join(ROOT, '.agents', 'plugins', 'marketplace.json'), 'utf8'));
|
|
116
133
|
assert.strictEqual(marketplace.name, 'harness-everything', 'marketplace should use the publication name, not a local-only label');
|
|
117
134
|
assert.strictEqual(marketplace.interface?.displayName, 'Harness Everything');
|
|
@@ -55,8 +55,10 @@ const {
|
|
|
55
55
|
createLearningOpportunity,
|
|
56
56
|
} = require(path.join(ROOT, 'hooks/scripts/lib/learning-opportunity.js'));
|
|
57
57
|
const { retrieveMemoryRecords } = require(path.join(ROOT, 'multi-agent-workspace/scripts/index_memory.js'));
|
|
58
|
+
const telemetry = require(path.join(ROOT, 'hooks/scripts/lib/telemetry.js'));
|
|
59
|
+
const { buildReport } = require(path.join(ROOT, 'telemetry/scripts/report.js'));
|
|
58
60
|
|
|
59
|
-
console.log('=== #141 Self-Evolve Closed Loop Phase 1-
|
|
61
|
+
console.log('=== #141 Self-Evolve Closed Loop Phase 1-4 Mechanism ===');
|
|
60
62
|
|
|
61
63
|
try {
|
|
62
64
|
const tracker = path.join(ROOT, 'hooks/scripts/rule-of-3-tracker.js');
|
|
@@ -248,6 +250,15 @@ try {
|
|
|
248
250
|
}).candidate;
|
|
249
251
|
check(retrievedState.state === 'retrieved' && retrievedState.outcome.evidenceRef === 'retrieval-fixture:REQ-141', 'later retrieval can advance the candidate lifecycle with evidence');
|
|
250
252
|
|
|
253
|
+
const validatedState = observeCandidate({
|
|
254
|
+
workspace,
|
|
255
|
+
sessionId: verifySession,
|
|
256
|
+
candidateId: verifyCandidate.candidateId,
|
|
257
|
+
outcome: 'validated',
|
|
258
|
+
evidence: 'paired-or-later-outcome-fixture:REQ-141',
|
|
259
|
+
}).candidate;
|
|
260
|
+
check(validatedState.state === 'validated', 'later outcome evidence can advance a retrieved lesson to validated');
|
|
261
|
+
|
|
251
262
|
const duplicate = createLearningOpportunity({
|
|
252
263
|
session_id: ruleSession,
|
|
253
264
|
cwd: workspace,
|
|
@@ -287,6 +298,30 @@ try {
|
|
|
287
298
|
check(sourceHook.includes('createLearningOpportunity') && verifierHook.includes('createLearningOpportunity'), 'negative-control anchors require both runtime emitters');
|
|
288
299
|
check(!sourceHook.includes('persistMemory(') && !verifierHook.includes('persistMemory('), 'runtime recovery hooks cannot directly persist memory');
|
|
289
300
|
|
|
301
|
+
const telemetryEvents = telemetry.readEvents(telemetry.telemetryFile(workspace, { cwd: workspace }));
|
|
302
|
+
const telemetryReport = buildReport(telemetryEvents);
|
|
303
|
+
const lessonEvents = new Set(telemetryEvents.filter(event => !event.invalid).map(event => event.event));
|
|
304
|
+
for (const expected of [
|
|
305
|
+
'learning_opportunity', 'lesson_proposed', 'lesson_screened', 'lesson_evaluated',
|
|
306
|
+
'lesson_accepted', 'lesson_rejected', 'lesson_inconclusive', 'lesson_persisted',
|
|
307
|
+
'lesson_retrieved', 'lesson_validated',
|
|
308
|
+
]) {
|
|
309
|
+
check(lessonEvents.has(expected), 'self-evolve lifecycle emits telemetry event: ' + expected);
|
|
310
|
+
}
|
|
311
|
+
check(telemetryReport.selfEvolve.funnel.opportunities >= 3 &&
|
|
312
|
+
telemetryReport.selfEvolve.funnel.accepted >= 1 &&
|
|
313
|
+
telemetryReport.selfEvolve.funnel.inconclusive >= 1 &&
|
|
314
|
+
telemetryReport.selfEvolve.funnel.rejected >= 1 &&
|
|
315
|
+
telemetryReport.selfEvolve.funnel.persisted >= 1 &&
|
|
316
|
+
telemetryReport.selfEvolve.funnel.retrieved >= 1 &&
|
|
317
|
+
telemetryReport.selfEvolve.funnel.validated >= 1,
|
|
318
|
+
'telemetry report exposes opportunity -> disposition -> persisted -> retrieved -> validated funnel');
|
|
319
|
+
const telemetryText = fs.readFileSync(telemetry.telemetryFile(workspace, { cwd: workspace }), 'utf8');
|
|
320
|
+
check(!telemetryText.includes('Always verify recovery.test.js') &&
|
|
321
|
+
!telemetryText.includes('retrieval-fixture:REQ-141') &&
|
|
322
|
+
!telemetryText.includes('SECRET_OUTPUT_SHOULD_NOT_BE_RETAINED'),
|
|
323
|
+
'lesson telemetry excludes generalized rules, evidence refs, and raw runtime output');
|
|
324
|
+
|
|
290
325
|
const lessonSchema = JSON.parse(fs.readFileSync(path.join(ROOT, 'self-evolve/schemas/lesson-candidate.schema.json'), 'utf8'));
|
|
291
326
|
check(lessonSchema.properties?.state?.enum?.includes('inconclusive') && lessonSchema.properties?.trigger?.properties?.type?.enum?.includes('verifier-fail-pass'), 'versioned lesson schema covers lifecycle and trigger vocabulary');
|
|
292
327
|
|
|
@@ -307,5 +342,5 @@ try {
|
|
|
307
342
|
fs.rmSync(tempRoot, { recursive: true, force: true });
|
|
308
343
|
}
|
|
309
344
|
|
|
310
|
-
console.log(`\n${failed === 0 ? 'PASS' : 'FAIL'}: #141 self-evolve closed loop phase 1-
|
|
345
|
+
console.log(`\n${failed === 0 ? 'PASS' : 'FAIL'}: #141 self-evolve closed loop phase 1-4 mechanism (${failed} failure${failed === 1 ? '' : 's'})`);
|
|
311
346
|
process.exit(failed === 0 ? 0 : 1);
|
package/ci/telemetry.test.js
CHANGED
|
@@ -102,6 +102,32 @@ async function main() {
|
|
|
102
102
|
check(report.skills[0].invocationCount === 1 && report.skills[0].toolEventCount === 1, 'aggregation retains invocation and attributed-tool counts');
|
|
103
103
|
check(report.semantics.activeWindowMs.includes('not CPU'), 'report documents active-window semantics instead of calling it runtime');
|
|
104
104
|
|
|
105
|
+
const lessonId = 'lesson-0123456789abcdef01234567';
|
|
106
|
+
for (const event of ['learning_opportunity', 'lesson_proposed', 'lesson_screened', 'lesson_evaluated', 'lesson_accepted', 'lesson_persisted', 'lesson_retrieved']) {
|
|
107
|
+
const emitted = telemetry.emitLessonTelemetry({
|
|
108
|
+
event,
|
|
109
|
+
root: workspace,
|
|
110
|
+
sessionId: session,
|
|
111
|
+
candidateId: lessonId,
|
|
112
|
+
status: 'success',
|
|
113
|
+
reasonCodes: ['fixture-lifecycle'],
|
|
114
|
+
});
|
|
115
|
+
check(emitted.ok === true, 'lesson lifecycle telemetry accepts privacy-safe event: ' + event);
|
|
116
|
+
}
|
|
117
|
+
const lifecycleEvents = telemetry.readEvents(file);
|
|
118
|
+
const lifecycleReport = buildReport(lifecycleEvents);
|
|
119
|
+
check(lifecycleReport.skills.length === 1 && lifecycleReport.skills[0].skillName === 'tdd',
|
|
120
|
+
'lesson lifecycle events do not contaminate skill execution aggregates');
|
|
121
|
+
check(lifecycleReport.selfEvolve.candidateCount === 1 &&
|
|
122
|
+
lifecycleReport.selfEvolve.funnel.opportunities === 1 &&
|
|
123
|
+
lifecycleReport.selfEvolve.funnel.accepted === 1 &&
|
|
124
|
+
lifecycleReport.selfEvolve.funnel.persisted === 1 &&
|
|
125
|
+
lifecycleReport.selfEvolve.funnel.retrieved === 1,
|
|
126
|
+
'report projects one correlated self-evolve opportunity -> accepted -> persisted -> retrieved funnel');
|
|
127
|
+
const lifecycleSerialized = fs.readFileSync(file, 'utf8');
|
|
128
|
+
check(!lifecycleSerialized.includes(lessonId) && !lifecycleSerialized.includes(session),
|
|
129
|
+
'lesson telemetry hashes candidate/session identities instead of retaining raw IDs');
|
|
130
|
+
|
|
105
131
|
const forbidden = telemetry.emitTelemetry({
|
|
106
132
|
event: 'skill.invoke',
|
|
107
133
|
host: 'claude',
|
|
@@ -173,7 +199,11 @@ async function main() {
|
|
|
173
199
|
}
|
|
174
200
|
|
|
175
201
|
const schema = JSON.parse(fs.readFileSync(path.join(ROOT, 'telemetry/schemas/event.schema.json'), 'utf8'));
|
|
176
|
-
check(schema.properties?.timing?.properties?.activeWindowMs &&
|
|
202
|
+
check(schema.properties?.timing?.properties?.activeWindowMs &&
|
|
203
|
+
schema.properties?.event?.enum?.includes('tool.observed') &&
|
|
204
|
+
schema.properties?.event?.enum?.includes('learning_opportunity') &&
|
|
205
|
+
schema.properties?.event?.enum?.includes('lesson_retrieved'),
|
|
206
|
+
'versioned telemetry schema preserves timing plus self-evolve lifecycle vocabulary');
|
|
177
207
|
|
|
178
208
|
} finally {
|
|
179
209
|
if (priorHome === undefined) delete process.env.HARNESS_STATE_HOME;
|
package/docs/architecture.md
CHANGED
|
@@ -73,6 +73,23 @@ For selected Fable topologies on Claude:
|
|
|
73
73
|
|
|
74
74
|
Other topologies use their own applicable mechanisms: loop budgets, regular verification stop-gates, action gates, and task-specific skills. Mechanism coverage is not assumed identical across hosts.
|
|
75
75
|
|
|
76
|
+
### Scoped runtime advisories and capabilities
|
|
77
|
+
|
|
78
|
+
Two kernel mechanisms adjust plans without changing the mandatory-workflow contract:
|
|
79
|
+
|
|
80
|
+
- **Ensemble policy (`harness-everything/scripts/ensemble-policy.js`):** an advisory plan annotation, not a separate topology. It is selected only when uncertainty is high (or stakes are high) **and** the task asks for comparable outputs or preserves explicit disagreement **and** the selected strategy is already `fable-*`. Creative generation, mechanical bulk work, an explicit user prohibition, unavailable subagents, or a blocked base plan force exclusion. When selected, the plan caps at 3 candidates with `preserve-disagreement` synthesis, an independent verifier, and `parallel-self-consistency` pattern invariants. Covered by deterministic mechanism tests; no live-host effectiveness claim follows from the annotation alone.
|
|
81
|
+
- **Single-use memory capability (`kernel-router.js#issueMemoryCapability`):** when the selected plan permits memory writes, the router issues one capability token bound to `sessionId`/`workflowId` with a stored SHA-256 hash (`memoryAuthorization`, coordinator-only writer role, `usedAt` tracking). Plans with `memory.write === 'none'` receive no capability. This binds a memory write to the workflow that authorized it; it is not a general credential and proves nothing about a live host honoring the binding.
|
|
82
|
+
|
|
83
|
+
### PreToolUse guard trio and denied-mutation probes
|
|
84
|
+
|
|
85
|
+
On the Claude hook path, three narrowly scoped `PreToolUse` guards sit alongside the workflow/action gates:
|
|
86
|
+
|
|
87
|
+
- `boundary-guard.js` (Grep/Glob/Read): hard-blocks whole-file reads over 512KB without `offset`/`limit` and searches inside known noise directories (`node_modules`, `.git`, build output, etc.). Fails open on parse/lookup errors.
|
|
88
|
+
- `depth-guard.js` (Write): blocks overwriting an existing file that was never Read earlier in the session transcript. New files are unaffected. Fails open on parse/lookup errors.
|
|
89
|
+
- `context-compact.js`: estimates working-tree context pressure from `git status`/`git diff --numstat` so later stages can compact or halt before lost-in-the-middle degradation.
|
|
90
|
+
|
|
91
|
+
Shell mutation accounting is per-tool-call: `workflow-isolation.js` fingerprints observed effects per tool-use identity, `state-persist.js` settles probes in a single ordered handler, and `workflow-mutation-denied.js` discards probes for denied shell executions so a denial never counts as an observed mutation. See [runtime transitions and limitations](workflow-runtime.md). These are mechanism-tested behaviors on the packaged hook surface, not proof that a live session loaded or fired them.
|
|
92
|
+
|
|
76
93
|
## Integration Touchpoints
|
|
77
94
|
|
|
78
95
|
Harness aligns to each host's actual lifecycle/tool APIs. Shared skill text defines a contract; only supported host mechanisms can mechanically block or observe particular transitions.
|
package/docs/audit.md
CHANGED
|
@@ -2,17 +2,58 @@
|
|
|
2
2
|
|
|
3
3
|
Maintainer-facing audit record. If you just want to know whether Harness works and how to verify it yourself, start at [VERIFICATION.md](../VERIFICATION.md) instead — this file records *how the scores below were obtained* and what changed between audit cycles.
|
|
4
4
|
|
|
5
|
-
> **Historical snapshot boundary:** the
|
|
5
|
+
> **Historical snapshot boundary:** the scorecards below are dated audits and are intentionally preserved as evidence of what was measured on each date. Platform capabilities have changed since the 2026-09-01 snapshot (including the OpenAI/Codex local plugin work and the OpenCode plugin implementation). Do not treat any dated platform row as current-state documentation; use [platform-capabilities.md](platform-capabilities.md) for the current matrix.
|
|
6
6
|
|
|
7
|
-
**Last self-audited: 2026-09-
|
|
7
|
+
**Last self-audited: 2026-09-18**, by running the deterministic test suite and gates on macOS (Node.js 24.14.1) — not by reading the code and assuming it works. The 2026-09-01 Windows 11 snapshot is preserved below. Live-host and behavioral evidence layers were not re-run in this cycle; retained artifacts are referenced, not re-measured.
|
|
8
8
|
|
|
9
|
-
## The 2026-
|
|
9
|
+
## The 2026-09-18 audit cycle
|
|
10
|
+
|
|
11
|
+
Measured on `docs/sync-skills-and-mechanisms` at `45f2123` (docs-only delta over v0.11.6): 26/26 on-disk canonical skills, 26/26 routing-eval directories (`evals/` also holds `evaluation-reports.md`), and the following gate results:
|
|
12
|
+
|
|
13
|
+
| Gate | Result on 2026-09-18 |
|
|
14
|
+
|---|---|
|
|
15
|
+
| `npm test` (self-regression, 43 passing checks) | Green except one pre-existing failure: `mechanism-30-opencode-plugin-loadability`, reproduced on the clean tree and caused by leftover `.worktrees/docs-skill-catalog` fixtures asserting `.mjs` destinations — not by product code |
|
|
16
|
+
| `npm run test:mutations` | Passed: 8 production mutations rejected by focused tests |
|
|
17
|
+
| `npm run test:consistency` (incl. doc-capability + repo-contract) | Passed |
|
|
18
|
+
| `npm run test:references` | Passed: 66 skill path references resolve across 26 skills |
|
|
19
|
+
| `npm run test:collision` | Passed: no description collisions at 0.75 threshold |
|
|
20
|
+
| `npm run test:routing:skills` | Passed: 34 positive cases across 26 direct skills; 4 nested skills classified |
|
|
21
|
+
| `npm run test:routing:invariants` | Passed: 275 checks, 0 failures (incl. workflow execution enforcement) |
|
|
22
|
+
| `node ci/disclosure-check.js` | Passed: 26 skills, 26 workflow docs |
|
|
23
|
+
| `npm run test:plugin:openai` / `test:plugin:submission` / `test:platform:compatibility` / `test:release` | All passed; release catalog green for v0.11.6 at 26/26 |
|
|
24
|
+
| `waza tokens check` | All 26 canonical skills within the 500-token limit; the single exceedance is the intentional `eval-framework/fixtures/over-budget-skill` negative control (855 tokens, exists to exercise the failure path) |
|
|
25
|
+
|
|
26
|
+
Since the 2026-09-01 snapshot, the product gained the mandatory-workflow contract (#142), runtime budget enforcement (#143), structured action gate (#144), memory governance (#145), self-evolve closed loop (#146), telemetry core (#147), contract-integrity phase 1 (#148), workflow controller recovery and isolation hardening (#150/#152/#154/#156/#158), observed-mutation accounting (#160), the Codex local plugin plus Claude certification boundary (#123), OpenCode `.js` loadability guard and partial live-host evidence (#128/#129), and the paired-benchmark contract (#130) — all covered by deterministic mechanism tests. The docs lag this cycle closed: stale `docs/workflows` rewrites, the README index gaps, and the previously undocumented ensemble/memory/guard/probe mechanisms are synced in the same change as this audit entry.
|
|
27
|
+
|
|
28
|
+
## Five Core Verification Criteria — 2026-09-18 re-measurement
|
|
29
|
+
|
|
30
|
+
| Criterion | Score | Verified basis |
|
|
31
|
+
|---|---|---|
|
|
32
|
+
| **Skill Description Completeness** | 10/10 | 26/26 skill directories carry complete frontmatter and the required trigger sections, verified by the consistency gate in this cycle. Internal hooks remain intentionally non-routable. |
|
|
33
|
+
| **Routing Accuracy** | 9/10 | 34/34 positive prompts across all 26 skills plus 275/275 invariant-routing checks in this cycle. Waza generalization (ambiguous/metaphorical prompts) and live model sessions remain unmeasured. |
|
|
34
|
+
| **Test Coverage of All Skills** | 9.5/10 | Self-regression now spans syntax, CLI, routing matrix, positive route coverage, invariant routing, references, behavioral-case structure, Fable contract, mutations, and 40+ mechanism suites. Waza full-matrix verify and live sessions remain separate on-demand evidence; `mechanism-30` is red only where the stale `.worktrees` leftover exists. |
|
|
35
|
+
| **Configuration Balance** | 9/10 | Hard `exit(2)` blocking hooks on Claude Code, mechanism-tested local Codex plugin package, and partial OpenCode live-host evidence (project `.js` scope, 1.18.31 macOS) — all centralized in `docs/platform-capabilities.md`. Live parity beyond the retained artifacts is still unclaimed. |
|
|
36
|
+
| **Workflow Conformance** | 9/10 | 26/26 skills have matching workflow documents (two stale ones rewritten in this cycle), the selected-workflow contract with escape/budget/stop-gate semantics is mechanism-tested, and disclosure passes. Runtime tool-call sequence conformance remains host-dependent and is not claimed. |
|
|
37
|
+
|
|
38
|
+
## Overall Scorecard — 2026-09-18
|
|
39
|
+
|
|
40
|
+
| Category | Score | Notes |
|
|
41
|
+
|---|---|---|
|
|
42
|
+
| **Architecture** | 9/10 | Per-session state isolation, worktree-gated Tier 3 mutation, per-tool mutation probes settled in one ordered handler, and single-use memory capabilities — all mechanism-tested in this cycle. |
|
|
43
|
+
| **Test Coverage** | 9.5/10 | 43 passing self-regression checks, 8/8 mutations rejected, 66/66 references resolve. Live model evaluation remains on-demand and is not represented by a local simulation. |
|
|
44
|
+
| **README Completeness** | 9.5/10 | Catalog counts, layer labels, route coverage, and the 26-skill tree match after this cycle's index fix (`contract-integrity`/`telemetry`/`eval-framework` rows added). |
|
|
45
|
+
| **Maintainability** | 9/10 | ~600 commits across 20+ PRs since 09-01 landed without breaking the consistency/release/disclosure gates; new non-skill directories are documented as non-skills rather than left ambiguous. |
|
|
46
|
+
| **Skills Design** | 9.5/10 | All 26 skills keep the Skill Contract format, `USE FOR`/`DO NOT USE FOR` sections, and the 500-token limit (verified by waza in this cycle); internal hooks remain intentionally non-routable. |
|
|
47
|
+
| **Agent Compatibility** | 9/10 | Claude hard-mechanism support measured, Codex local plugin mechanism-tested, OpenCode partial live evidence retained — see the current platform matrix, not this row, for status. |
|
|
48
|
+
| **Beginner Friendliness** | 7.5/10 | Unchanged since 09-01: Tier Routing / Rule of 3 / session-scoped state remain load-bearing concepts. The two rewritten workflow docs reduce stale-doc confusion but add no onboarding track. Not addressed in this audit round. |
|
|
49
|
+
|
|
50
|
+
## The 2026-07-23 mis-measurement incident (preserved)
|
|
10
51
|
|
|
11
52
|
Seven independent AI-model audits (Gemini 3.1 Pro, Gemini 3.5 Flash, GPT/Copilot on Mistral Medium/Small, and others) ran the same week and disagreed sharply on whether core hooks even functioned. Three of them tested `rule-of-3.js`, `boundary-guard.js`, and `state-persist.js` by piping JSON through `echo '...' | node script.js` in Windows Git Bash, which mangles stdin/TTY state and produced false "broken" verdicts. Re-running the identical payloads through Node's own `child_process` stdin API (the technique VERIFICATION.md's recipes now use) showed every one of those mechanisms working exactly as documented — the scores below reflect that corrected, verified state, not the average of the seven reports.
|
|
12
53
|
|
|
13
54
|
This incident is why VERIFICATION.md's recipes were rewritten to be Windows-safe (`node -e` stdin instead of a shell `echo` pipe), and why the §2 mechanism checks were automated as `ci/mechanism-test.js` (`npm run test:mechanism`) — copy-paste recipes that can be mis-executed are not a reliable verification substrate.
|
|
14
55
|
|
|
15
|
-
## Five Core Verification Criteria (per VERIFICATION.md §5a)
|
|
56
|
+
## Five Core Verification Criteria — 2026-09-01 snapshot (per VERIFICATION.md §5a)
|
|
16
57
|
|
|
17
58
|
| Criterion | Score | Verified basis |
|
|
18
59
|
|---|---|---|
|
|
@@ -22,7 +63,7 @@ This incident is why VERIFICATION.md's recipes were rewritten to be Windows-safe
|
|
|
22
63
|
| **Configuration Balance** | 8.5/10 | **Historical 2026-09-01 result:** hard `exit(2)` blocking hooks were measured on Claude Code and the other then-installed platform paths were evaluated as advisory. This row predates the later OpenAI/Codex local plugin and OpenCode plugin work; see `docs/platform-capabilities.md` for current status. |
|
|
23
64
|
| **Workflow Conformance** | 8.5/10 | Every skill in the snapshot had a matching workflow document, and `ci/skill-routing-check.js` executed every positive route case against the real router. Runtime tool-call sequence conformance remained host-dependent and was not claimed. |
|
|
24
65
|
|
|
25
|
-
## Overall Scorecard
|
|
66
|
+
## Overall Scorecard — 2026-09-01 snapshot
|
|
26
67
|
|
|
27
68
|
| Category | Score | Notes |
|
|
28
69
|
|---|---|---|
|
|
@@ -36,6 +77,12 @@ This incident is why VERIFICATION.md's recipes were rewritten to be Windows-safe
|
|
|
36
77
|
|
|
37
78
|
## Change log by audit cycle
|
|
38
79
|
|
|
80
|
+
### 2026-09-18
|
|
81
|
+
- Re-measured the deterministic suite and gates on macOS (Node.js 24.14.1): 43 passing self-regression checks, 8/8 mutations rejected, 66/66 references resolve, 34/34 positive routes, 275/275 invariant checks, disclosure 26/26, release catalog green for v0.11.6. Sole red is the pre-existing `mechanism-30` failure from leftover `.worktrees/docs-skill-catalog` fixtures, reproduced on the clean tree.
|
|
82
|
+
- Closed the docs lag accumulated since 09-01 in the same change: rewrote the stale `docs/workflows/harness-everything.md` and `install-cognitive-os.md`, added the missing README index rows (`contract-integrity`/`telemetry`/`eval-framework`), and documented the ensemble policy, single-use memory capability, guard trio, and mutation-probe lifecycle in `docs/architecture.md` / `docs/workflow-runtime.md`.
|
|
83
|
+
- Product changes since 09-01 now covered by mechanism tests: mandatory-workflow contract, budget enforcement, structured action gate, memory governance, self-evolve closed loop, telemetry core, contract-integrity phase 1, controller recovery/isolation hardening, observed-mutation accounting, Codex local plugin, OpenCode partial live evidence, paired-benchmark contract. Live-host and behavioral layers were not re-run; retained artifacts stand.
|
|
84
|
+
- Beginner Friendliness stays 7.5/10: still no onboarding track. Candidate for the next cycle.
|
|
85
|
+
|
|
39
86
|
### 2026-09-01
|
|
40
87
|
- Fable v3 integration exposed explicit Haiku, Sonnet, and Opus entrypoints, with deterministic model selection and visible inline fallback or blocked escalation in `fable-mode/model-matrix.json` and `fable-mode/scripts/model-selector.js`.
|
|
41
88
|
- The workflow used native host TODO tracking or Markdown checklists. The older shared TODO CLI/state-machine references below are retained only as historical audit evidence; no current runtime, test, or active workflow depends on them.
|
package/docs/release-evidence.md
CHANGED
|
@@ -9,6 +9,9 @@ The following evidence was collected on 2026-09-07 before the issue #20 integrat
|
|
|
9
9
|
| Version | Registry observation | GitHub release | Workflow run | Gate and publish result |
|
|
10
10
|
| --- | --- | --- | --- | --- |
|
|
11
11
|
| 0.3.6 | `npm view harness-everything version dist-tags --json`: version and latest are `0.3.6` | `v0.3.6`, published 2026-09-01T03:50:44Z | [33466676632](https://github.com/dyphn1/Harness-everything/actions/runs/33466676632), commit `5aa74119d08ff241a7d6fe8f163a6a0d40c3c932` | `gate=success`, `publish=success` |
|
|
12
|
+
| 0.11.6 | `npm view harness-everything version dist-tags --json` (collected 2026-09-18): version and latest are `0.11.6` | `v0.11.6`, published 2026-09-18T12:51:58Z | [35346673284](https://github.com/dyphn1/Harness-everything/actions/runs/35346673284), commit `23d87db8230dcb524651dc67e932f54aa6f5c737` | `gate=success` (12/12 jobs incl. skill-quality, runtime-floor, self-regression x3 OS, consistency x3 OS, installer-e2e x3 OS, release-semantics), `publish=success` (job `release`) |
|
|
13
|
+
|
|
14
|
+
Intermediate versions between 0.3.6 and 0.11.6 were published via the same tag-driven workflow but were not individually ledgered here; the rows above are the two deliberately collected observations. A registry/GitHub listing alone is still not a completed row — each field must be a command output or inspectable URL.
|
|
12
15
|
|
|
13
16
|
The source capture for this row is the local review artifact `.git/issue-review-20260907/release-evidence.md`. That review artifact is not expected to be present in every checkout; it is historical evidence, not a release artifact shipped in the npm package.
|
|
14
17
|
|
package/docs/workflow-runtime.md
CHANGED
|
@@ -63,6 +63,19 @@ have effects a hook cannot infer. OS/host sandboxing is needed to contain them.
|
|
|
63
63
|
Agent-writable state is also not tamper-proof. These mechanisms prevent tested
|
|
64
64
|
bypasses; they do not establish durable containment against a malicious agent.
|
|
65
65
|
|
|
66
|
+
## Mutation probes
|
|
67
|
+
|
|
68
|
+
Shell-effect accounting is keyed per tool call, not per command text. The gate
|
|
69
|
+
registers a pending probe per shell tool-use identity (`workflow-isolation.js`),
|
|
70
|
+
`state-persist.js` settles probes in a single ordered handler, and
|
|
71
|
+
`workflow-mutation-denied.js` discards the probe when that shell execution is
|
|
72
|
+
denied — a denial is never recorded as an observed mutation. Staging-insensitive
|
|
73
|
+
fingerprinting keeps the comparison on visible content, so metadata-only Git
|
|
74
|
+
operations do not register as workspace effects. These lifecycle semantics are
|
|
75
|
+
covered by deterministic workflow mechanism tests (`ci/mechanism-2ah-*`); live
|
|
76
|
+
host loading and behavioral improvement still require separately retained host
|
|
77
|
+
traces and paired evaluations.
|
|
78
|
+
|
|
66
79
|
## Escape, replan, and completion
|
|
67
80
|
|
|
68
81
|
Escape names one stage in the correlated run and records the uncovered scope,
|
|
@@ -1,63 +1,73 @@
|
|
|
1
1
|
# Workflow: Environment Detection
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Detect OS, shell variant, and available dev tools at session start so commands use the right path, variable, and CLI syntax and avoid repeated execution errors.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Source of truth: `environment-detection/SKILL.md`.
|
|
6
6
|
|
|
7
7
|
## 1. Skill Behavior Workflow
|
|
8
8
|
|
|
9
|
-
This section visualizes how the `environment-detection` skill executes internally, detailing the sequence of operations, state transitions, and evaluation steps.
|
|
10
|
-
|
|
11
9
|
```mermaid
|
|
12
10
|
graph TD
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
SelfHeal --> AlignSyntax["Adopt Path Slash (/ vs \\) & Env Var Syntax ($VAR vs %VAR%)"]
|
|
22
|
-
AlignSyntax --> End([Environment Context Established])
|
|
11
|
+
SessionStart([Session start or complex terminal sequence]) --> Preflight[Run preflight.js from skill dir]
|
|
12
|
+
Preflight --> PreflightOk{Preflight succeeded?}
|
|
13
|
+
PreflightOk -->|yes| ParseOut[Parse OS shell PATH and CLIs]
|
|
14
|
+
PreflightOk -->|no| FallbackProbe[Inspect environment_info and probe shell]
|
|
15
|
+
FallbackProbe --> ParseOut
|
|
16
|
+
ParseOut --> SelfHealAudit[Audit harness touchpoints with self-heal.js]
|
|
17
|
+
SelfHealAudit --> AdoptSyntax[Adopt shell-specific syntax]
|
|
18
|
+
AdoptSyntax --> DoneCtx([Session context aligned])
|
|
23
19
|
```
|
|
24
20
|
|
|
25
|
-
|
|
21
|
+
```mermaid
|
|
22
|
+
graph TD
|
|
23
|
+
Adopted[Adopted syntax context] --> GitBash[Git Bash: forward slash and dollar-VAR with Unix cmds]
|
|
24
|
+
Adopted --> PowerShell[PowerShell: env-prefix vars with cmdlets]
|
|
25
|
+
Adopted --> CmdShell[CMD: backslash and percent-VAR with dir del copy]
|
|
26
|
+
GitBash --> GuardCwd[Stay inside process cwd]
|
|
27
|
+
PowerShell --> GuardCwd
|
|
28
|
+
CmdShell --> GuardCwd
|
|
29
|
+
GuardCwd --> FailCount{Same command failed 3 times?}
|
|
30
|
+
FailCount -->|yes| ZoomEsc[Trigger zoom-out]
|
|
31
|
+
FailCount -->|no| ContinueRun[Continue with aligned syntax]
|
|
32
|
+
```
|
|
26
33
|
|
|
27
34
|
## 2. Triggering and Routing Path
|
|
28
35
|
|
|
29
|
-
This diagram illustrates how the `environment-detection` skill is triggered through user requests or developer actions, and how it integrates or chains together with other companion skills in the Harness OS ecosystem to form unified workflows.
|
|
30
|
-
|
|
31
36
|
```mermaid
|
|
32
37
|
graph LR
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
38
|
+
StartTrigger[Session start request] --> EnvDetect[environment-detection SKILL]
|
|
39
|
+
ComplexSeq[Complex terminal sequence] --> EnvDetect
|
|
40
|
+
EnvDetect --> AlignedRun[Aligned command execution]
|
|
41
|
+
AlignedRun --> RepeatedFail{Three failures on same command?}
|
|
42
|
+
RepeatedFail -->|yes| ZoomOut[zoom-out]
|
|
43
|
+
RepeatedFail -->|no| AlignedRun
|
|
37
44
|
```
|
|
38
45
|
|
|
39
|
-
|
|
46
|
+
## 3. Real-World Use Case
|
|
40
47
|
|
|
41
|
-
|
|
48
|
+
A session starts on Windows with PowerShell as the active shell. The agent needs to list files and check Node availability before running tests.
|
|
42
49
|
|
|
43
|
-
|
|
50
|
+
1. Run `node "<skill-dir>/scripts/preflight.js"` to detect Windows + PowerShell + available CLIs.
|
|
51
|
+
2. Adopt PowerShell syntax for paths and env vars instead of Git Bash assumptions.
|
|
52
|
+
3. If `preflight.js` cannot run, inspect `<environment_info>` and probe with minimal echo/env commands, then adopt syntax.
|
|
53
|
+
4. Stay inside `process.cwd()`; ignore other workspace, history, or temp paths shown by the IDE.
|
|
54
|
+
5. If the same aligned command still fails three times, stop retrying the syntax and trigger `zoom-out`.
|
|
44
55
|
|
|
45
56
|
```mermaid
|
|
46
57
|
graph TD
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
58
|
+
AgentGoal[Need to list files and check Node on Windows] --> DetectEnv[Run session-start detection]
|
|
59
|
+
DetectEnv --> FoundShell[Detected PowerShell on Windows]
|
|
60
|
+
FoundShell --> UseCmd[Use PowerShell syntax for listing and env lookup]
|
|
61
|
+
UseCmd --> CmdResult{Command works?}
|
|
62
|
+
CmdResult -->|yes| ProceedTask[Proceed with task]
|
|
63
|
+
CmdResult -->|no after 3 tries| ZoomStep[Trigger zoom-out]
|
|
53
64
|
```
|
|
54
65
|
|
|
55
|
-
---
|
|
56
|
-
|
|
57
66
|
## 4. Verification Check
|
|
58
67
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
- [ ]
|
|
62
|
-
- [ ]
|
|
63
|
-
- [ ]
|
|
68
|
+
- [ ] Detection ran at session start via `environment-detection/scripts/preflight.js`, with `<environment_info>` inspection and probing used only as fallback
|
|
69
|
+
- [ ] Adopted syntax matches detected shell: Git Bash uses `/`, `$VAR`, Unix cmds without `dir`/`del`; PowerShell uses `$env:VAR` and cmdlets; CMD uses `\`, `%VAR%`, `dir`/`del`/`copy` without Unix cmds
|
|
70
|
+
- [ ] All commands stayed inside `process.cwd()`; no commands ran outside the current project root
|
|
71
|
+
- [ ] No toolchain installation was attempted; scope stayed to detection, alignment, and touchpoint repair
|
|
72
|
+
- [ ] After three failures of the same command, execution stopped blind retry and triggered `zoom-out`
|
|
73
|
+
- [ ] Shell detail followed `environment-detection/references/shell-syntax-rules.md` where needed
|