harness-everything 0.38.0 → 0.40.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/AGENTS.md +79 -63
- package/CHANGELOG.md +32 -0
- package/benchmarks/results/reviews/pr353-r6-2026-10-22/README.md +76 -0
- package/benchmarks/results/reviews/pr353-r6-2026-10-22/a-reviews-b.md +191 -0
- package/benchmarks/results/reviews/pr353-r6-2026-10-22/b-reviews-a.md +100 -0
- package/benchmarks/results/reviews/pr353-r6-2026-10-22/baseline-probes.log +47 -0
- package/benchmarks/results/reviews/pr353-r6-2026-10-22/bom-red.log +85 -0
- package/benchmarks/results/reviews/pr353-r6-2026-10-22/bom-transition.txt +25 -0
- package/benchmarks/results/reviews/pr353-r6-2026-10-22/coordinator-probes.txt +84 -0
- package/benchmarks/results/reviews/pr353-r6-2026-10-22/cross-suite.txt +18 -0
- package/benchmarks/results/reviews/pr353-r6-2026-10-22/final-bom.log +3 -0
- package/benchmarks/results/reviews/pr353-r6-2026-10-22/final-consistency.log.gz +0 -0
- package/benchmarks/results/reviews/pr353-r6-2026-10-22/final-core.log +198 -0
- package/benchmarks/results/reviews/pr353-r6-2026-10-22/final-probes.log +27 -0
- package/benchmarks/results/reviews/pr353-r6-2026-10-22/final-producer.log +83 -0
- package/benchmarks/results/reviews/pr353-r6-2026-10-22/final-review.md +89 -0
- package/benchmarks/results/reviews/pr353-r6-2026-10-22/final-transitions.log +5 -0
- package/benchmarks/results/reviews/pr353-r6-2026-10-22/implementation-a.md +166 -0
- package/benchmarks/results/reviews/pr353-r6-2026-10-22/implementation-b.md +264 -0
- package/benchmarks/results/reviews/pr353-r6-2026-10-22/logs.sha256 +15 -0
- package/benchmarks/results/reviews/pr353-r6-2026-10-22/peer-a-probe.log +62 -0
- package/benchmarks/results/reviews/pr353-r6-2026-10-22/peer-a-probe.txt +313 -0
- package/benchmarks/results/reviews/pr353-r6-2026-10-22/peer-b-probe.log +51 -0
- package/benchmarks/results/reviews/pr353-r6-2026-10-22/peer-b-probe.txt +94 -0
- package/benchmarks/results/reviews/pr353-r6-2026-10-22/semantic-transitions.txt +25 -0
- package/benchmarks/results/reviews/pr353-r6-2026-10-22/source.sha256 +9 -0
- package/benchmarks/results/reviews/pr353-r6-2026-10-22/tests-a-on-b-core.log +201 -0
- package/benchmarks/results/reviews/pr353-r6-2026-10-22/tests-a-on-b-producer.log +82 -0
- package/benchmarks/results/reviews/pr353-r6-2026-10-22/tests-b-on-a-core.log +197 -0
- package/benchmarks/results/reviews/pr353-r6-2026-10-22/tests-b-on-a-producer.log +82 -0
- package/benchmarks/results/reviews/pr353-r6-2026-10-22/verify-all.log.gz +0 -0
- package/benchmarks/results/reviews/pr353-r6-2026-10-22/verify-gate-summary.json +22 -0
- package/ci/fixtures/doc-obligations/reconciliation-s2a/harness.js +489 -0
- package/ci/fixtures/doc-obligations/reconciliation-s2a/vectors.json +617 -0
- package/ci/mechanism-325-3b-s2a-core.test.js +840 -0
- package/ci/mechanism-325-3b-s2a-producer.test.js +564 -0
- package/code-review/SKILL.md +3 -3
- package/code-review/references/review-playbook.md +4 -0
- package/code-review/templates/finding.template.md +6 -0
- package/docs/doc-workflow-reconciliation.md +357 -0
- package/evals/zoom-out/tasks/negative-first-edge-case-review.yaml +16 -0
- package/evals/zoom-out/tasks/positive-repair-loop.yaml +15 -0
- package/harness-everything/SKILL.md +1 -1
- package/harness-everything/scripts/project-docs-resolver.js +42 -8
- package/harness-everything/scripts/routing-keywords.json +4 -0
- package/hooks/scripts/lib/doc-reconciliation-core.js +280 -0
- package/hooks/scripts/lib/doc-reconciliation-events.js +141 -0
- package/hooks/scripts/lib/doc-reconciliation-producer.js +206 -0
- package/multi-agent-workspace/SKILL.md +1 -1
- package/multi-agent-workspace/scripts/project-docs-resolver.js +42 -8
- package/opencode-plugin/plugin.json +1 -1
- package/package.json +2 -1
- package/plugins/harness-everything/.codex-plugin/plugin.json +1 -1
- package/plugins/harness-everything/hooks/scripts/lib/doc-reconciliation-core.js +280 -0
- package/plugins/harness-everything/hooks/scripts/lib/doc-reconciliation-events.js +141 -0
- package/plugins/harness-everything/hooks/scripts/lib/doc-reconciliation-producer.js +206 -0
- package/plugins/harness-everything/plugin.json +1 -1
- package/plugins/harness-everything/skills/code-review/SKILL.md +3 -3
- package/plugins/harness-everything/skills/code-review/references/review-playbook.md +4 -0
- package/plugins/harness-everything/skills/code-review/templates/finding.template.md +6 -0
- package/plugins/harness-everything/skills/harness-everything/SKILL.md +1 -1
- package/plugins/harness-everything/skills/harness-everything/scripts/project-docs-resolver.js +42 -8
- package/plugins/harness-everything/skills/harness-everything/scripts/routing-keywords.json +4 -0
- package/plugins/harness-everything/skills/multi-agent-workspace/SKILL.md +1 -1
- package/plugins/harness-everything/skills/multi-agent-workspace/scripts/project-docs-resolver.js +42 -8
- package/plugins/harness-everything/skills/to-spec/SKILL.md +1 -1
- package/plugins/harness-everything/skills/to-spec/scripts/project-docs-resolver.js +42 -8
- package/plugins/harness-everything/skills/zoom-out/SKILL.md +4 -3
- package/plugins/harness-everything/skills/zoom-out/references/circuit-breaker.md +7 -0
- package/plugins/harness-everything/skills/zoom-out/templates/zoom-out-report.template.md +4 -2
- package/sbom.cdx.json +7 -7
- package/scripts/errors-sync.js +90 -0
- package/to-spec/SKILL.md +1 -1
- package/to-spec/scripts/project-docs-resolver.js +42 -8
- package/zoom-out/SKILL.md +4 -3
- package/zoom-out/references/circuit-breaker.md +7 -0
- package/zoom-out/templates/zoom-out-report.template.md +4 -2
|
@@ -4,7 +4,7 @@ description: "Reflect-first circuit breaker - after 3 failures, stop edits, rebu
|
|
|
4
4
|
license: Apache-2.0
|
|
5
5
|
metadata:
|
|
6
6
|
author: Miya Daniel
|
|
7
|
-
version: 0.
|
|
7
|
+
version: 0.40.0
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# Zoom Out (Circuit Breaker)
|
|
@@ -15,7 +15,7 @@ Stop repeated failures, rebuild the facts, and choose a safe next step.
|
|
|
15
15
|
|
|
16
16
|
| Component | Specification |
|
|
17
17
|
| :--- | :--- |
|
|
18
|
-
| **Trigger / Input** | Three same-signature failures or an explicit loop/rethink request. |
|
|
18
|
+
| **Trigger / Input** | Three same-signature failures, a repair loop, or an explicit loop/rethink request. |
|
|
19
19
|
| **Expected Output** | Fact-checked report ending in `RESUME` or `ESCALATE`. |
|
|
20
20
|
| **State Mutations** | Writes the session `zoom-out-report.md`; reset may clear breaker state. |
|
|
21
21
|
| **Enforcement Gate** | `<skills-repo-root>/hooks/scripts/rule-of-3.js` plus a valid report; a later three-failure cycle requests another reflection. |
|
|
@@ -25,12 +25,13 @@ Stop repeated failures, rebuild the facts, and choose a safe next step.
|
|
|
25
25
|
1. After three same-signature failures, stop edits and do not ask the user yet.
|
|
26
26
|
2. Use read-only tools to restate the goal and check files, configuration, and logs.
|
|
27
27
|
3. Fill `<this-skill-dir>/templates/zoom-out-report.template.md` and end with `RESUME` or `ESCALATE`.
|
|
28
|
-
4. Resume only on an untried path; escalate genuine user decisions with options.
|
|
28
|
+
4. Resume only on an untried path; escalate genuine user decisions with options. Repair loop: inventory sites first.
|
|
29
29
|
5. If three more matching failures occur, run another zoom-out cycle. `npm run harness:reset` is only an optional manual state clear; record the insight with `self-evolve`.
|
|
30
30
|
|
|
31
31
|
## USE FOR:
|
|
32
32
|
- "you are stuck in a loop"
|
|
33
33
|
- "the same error keeps failing"
|
|
34
|
+
- "every round finds a new edge case"
|
|
34
35
|
- "rethink your assumptions"
|
|
35
36
|
|
|
36
37
|
## DO NOT USE FOR:
|
|
@@ -27,6 +27,13 @@ flowchart TD
|
|
|
27
27
|
## 1. Triggers
|
|
28
28
|
- **Rule of 3 (Repeated Failures)**: Attempting to fix the same error or test failure 3 times without progress.
|
|
29
29
|
- **Divergence**: Fixing one bug repeatedly introduces new secondary errors.
|
|
30
|
+
- **Repair loop (feature level)**: Two consecutive review or fix rounds on the same feature each surface new defects in the same decision class (for example "is this the trusted checker?"), even though every command succeeded.
|
|
31
|
+
- The Rule of 3 hook cannot see this. It counts same-signature command failures in one session. Successful review findings do not increment it, and unrelated successes can leave an existing count in place. New sessions and different failure signatures do not accumulate a feature's review history.
|
|
32
|
+
- The signal comes from review history: prior findings and their dispositions, the round count per class in an error ledger, or the reviewer noticing the pattern. It is a prompt to reflect, not a lock. The hook gate in the skill contract applies only to the three-failure trigger.
|
|
33
|
+
- "Same decision class" means the same acceptance decision under the same trust assumptions, possibly at different sites. "Same directory" or "validation" is too broad. Count a repeated or renamed finding once, and treat missing history as unknown, not zero.
|
|
34
|
+
- Phase 2 here means: list every finding so far by decision class, state the acceptance clause each violates, and inventory every site (callers, state readers, Stop consumers) that makes the same decision. Findings that map to no acceptance clause stay `unresolved` for the owner instead of becoming new fixes.
|
|
35
|
+
- RESUME by using the inventory to choose the smallest justified correction (which may be one shared fix, or no code change), then re-trace one normal end-to-end acceptance path. Unresolved findings need scope adjudication, not speculative repairs.
|
|
36
|
+
- A one-shot reviewer cannot see the previous round on its own. The packet carries the current acceptance anchor, a link to the previous comparable report with its revision, the prior finding IDs and dispositions, and the fix made since.
|
|
30
37
|
- **Goal Drift**: Execution strays far from the initial task objective.
|
|
31
38
|
- **User Instruction**: The user requests a step back ("zoom out", "step back", "stop and think").
|
|
32
39
|
|
|
@@ -3,12 +3,14 @@
|
|
|
3
3
|
|
|
4
4
|
## Failed Attempts
|
|
5
5
|
<attempt → underlying assumption → observed outcome>
|
|
6
|
-
**Failure Category:** <syntax|environment|test|timeout|permission|dependency|unknown>
|
|
6
|
+
**Failure Category:** <syntax|environment|test|timeout|permission|dependency|repair-loop|unknown>
|
|
7
|
+
**Repair-loop rounds (repair loop only):** <round → new finding → decision class → violated acceptance clause or `unresolved`>
|
|
7
8
|
|
|
8
9
|
## Verified Facts
|
|
9
10
|
<facts re-checked in Phase 2 with file paths>
|
|
10
11
|
**Files Checked:** <list at least 3 related files you actually read>
|
|
11
|
-
**Error Message Verified:** <copy the exact error message from the last failure>
|
|
12
|
+
**Error Message Verified:** <copy the exact error message from the last failure; for a repair loop with no error, write `none` and cite the latest finding instead>
|
|
13
|
+
**Sites Inventoried (repair loop only):** <every site making the same decision, including unchanged callers and consumers>
|
|
12
14
|
|
|
13
15
|
## Diagnosis
|
|
14
16
|
<comprehensive explanation of root cause>
|
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:ec1ab676-b0e1-5aa7-869d-8317e5674765",
|
|
6
6
|
"version": 1,
|
|
7
7
|
"metadata": {
|
|
8
|
-
"timestamp": "2026-10-
|
|
8
|
+
"timestamp": "2026-10-23T07:24:05.300Z",
|
|
9
9
|
"tools": [
|
|
10
10
|
{
|
|
11
11
|
"vendor": "Harness Everything",
|
|
12
12
|
"name": "generate-sbom.js",
|
|
13
|
-
"version": "0.
|
|
13
|
+
"version": "0.40.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.40.0",
|
|
19
19
|
"name": "harness-everything",
|
|
20
|
-
"version": "0.
|
|
21
|
-
"purl": "pkg:npm/harness-everything@0.
|
|
20
|
+
"version": "0.40.0",
|
|
21
|
+
"purl": "pkg:npm/harness-everything@0.40.0"
|
|
22
22
|
}
|
|
23
23
|
},
|
|
24
24
|
"components": [
|
|
@@ -2033,7 +2033,7 @@
|
|
|
2033
2033
|
]
|
|
2034
2034
|
},
|
|
2035
2035
|
{
|
|
2036
|
-
"ref": "pkg:npm/harness-everything@0.
|
|
2036
|
+
"ref": "pkg:npm/harness-everything@0.40.0",
|
|
2037
2037
|
"dependsOn": [
|
|
2038
2038
|
"pkg:npm/%40commitlint/cli@19.8.1",
|
|
2039
2039
|
"pkg:npm/%40commitlint/config-conventional@19.8.1",
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
// Regenerates .agents/harness-everything/errors/index.jsonl from the E-*.md records.
|
|
5
|
+
// `--check` compares instead of writing. Not wired into CI or hooks on purpose.
|
|
6
|
+
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const yaml = require('js-yaml');
|
|
10
|
+
|
|
11
|
+
const ROOT = path.resolve(__dirname, '..');
|
|
12
|
+
const DIR = path.join(ROOT, '.agents', 'harness-everything', 'errors');
|
|
13
|
+
const INDEX = path.join(DIR, 'index.jsonl');
|
|
14
|
+
const RECORD = /^E-\d{4}-[a-z0-9-]+\.md$/;
|
|
15
|
+
const REQUIRED = ['id', 'signature', 'class', 'scope', 'status'];
|
|
16
|
+
const SCOPES = new Set(['in', 'out', 'unresolved']);
|
|
17
|
+
const STATUSES = new Set(['open', 'lesson', 'mechanism']);
|
|
18
|
+
|
|
19
|
+
function parseRecord(file) {
|
|
20
|
+
const text = fs.readFileSync(path.join(DIR, file), 'utf8').replace(/\r\n/g, '\n');
|
|
21
|
+
const match = /^---\n([\s\S]*?)\n---\n/.exec(text);
|
|
22
|
+
if (!match) throw new Error(`${file}: missing YAML frontmatter`);
|
|
23
|
+
const meta = yaml.load(match[1]);
|
|
24
|
+
if (!meta || typeof meta !== 'object') throw new Error(`${file}: frontmatter is not a mapping`);
|
|
25
|
+
for (const key of REQUIRED) {
|
|
26
|
+
if (meta[key] === undefined || meta[key] === null || meta[key] === '') throw new Error(`${file}: missing ${key}`);
|
|
27
|
+
}
|
|
28
|
+
if (!file.startsWith(`${meta.id}-`)) throw new Error(`${file}: id ${meta.id} does not match the file name`);
|
|
29
|
+
if (!SCOPES.has(meta.scope)) throw new Error(`${file}: scope must be in, out or unresolved`);
|
|
30
|
+
if (!STATUSES.has(meta.status)) throw new Error(`${file}: status must be open, lesson or mechanism`);
|
|
31
|
+
const episodes = Array.isArray(meta.episodes) ? meta.episodes : [];
|
|
32
|
+
return {
|
|
33
|
+
id: meta.id,
|
|
34
|
+
signature: meta.signature,
|
|
35
|
+
class: meta.class,
|
|
36
|
+
title: meta.title || null,
|
|
37
|
+
scope: meta.scope,
|
|
38
|
+
status: meta.status,
|
|
39
|
+
sites: Array.isArray(meta.sites) ? meta.sites : [],
|
|
40
|
+
violates: meta.violates || null,
|
|
41
|
+
mechanism_ref: meta.mechanism_ref || null,
|
|
42
|
+
episodes: episodes.length,
|
|
43
|
+
rounds: episodes.map(e => ({
|
|
44
|
+
episode: e.episode || null,
|
|
45
|
+
// Round 0 is discovery, so the attempt count is the highest round number.
|
|
46
|
+
rounds: Array.isArray(e.rounds) ? Math.max(0, ...e.rounds.map(r => Number(r.round) || 0)) : null,
|
|
47
|
+
closed: e.closed === true,
|
|
48
|
+
})),
|
|
49
|
+
file: path.posix.join('.agents/harness-everything/errors', file),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function render() {
|
|
54
|
+
const files = fs.readdirSync(DIR).filter(f => RECORD.test(f)).sort();
|
|
55
|
+
const ids = new Set();
|
|
56
|
+
const lines = files.map(file => {
|
|
57
|
+
const record = parseRecord(file);
|
|
58
|
+
if (ids.has(record.id)) throw new Error(`${file}: duplicate id ${record.id}`);
|
|
59
|
+
ids.add(record.id);
|
|
60
|
+
return JSON.stringify(record);
|
|
61
|
+
});
|
|
62
|
+
return lines.length ? `${lines.join('\n')}\n` : '';
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function main() {
|
|
66
|
+
const check = process.argv.includes('--check');
|
|
67
|
+
let next;
|
|
68
|
+
try {
|
|
69
|
+
next = render();
|
|
70
|
+
} catch (error) {
|
|
71
|
+
console.error(`errors:sync: ${error.message}`);
|
|
72
|
+
process.exit(1);
|
|
73
|
+
}
|
|
74
|
+
const rel = path.relative(ROOT, INDEX).replace(/\\/g, '/');
|
|
75
|
+
if (check) {
|
|
76
|
+
const current = fs.existsSync(INDEX) ? fs.readFileSync(INDEX, 'utf8') : null;
|
|
77
|
+
if (current !== next) {
|
|
78
|
+
console.error(`${rel} is stale. Run npm run errors:sync.`);
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
console.log(`${rel} is current.`);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
fs.writeFileSync(INDEX, next, 'utf8');
|
|
85
|
+
console.log(`Updated ${rel}`);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (require.main === module) main();
|
|
89
|
+
|
|
90
|
+
module.exports = { render };
|
package/to-spec/SKILL.md
CHANGED
|
@@ -122,15 +122,17 @@ function readHostProjectDocsConfigs(workspaceRoot) {
|
|
|
122
122
|
return manifests;
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
-
function inspectHostProjectDocs(workspaceRoot) {
|
|
125
|
+
function inspectHostProjectDocs(workspaceRoot, readSource = null) {
|
|
126
126
|
const entries = [];
|
|
127
127
|
for (const home of PLATFORM_HOMES) {
|
|
128
128
|
const file = path.join(workspaceRoot, home, 'harness-everything', 'manifest.json');
|
|
129
|
-
|
|
129
|
+
const captured = readSource ? readSource(file) : null;
|
|
130
|
+
if (captured ? captured.presence === 'absent' : !fs.existsSync(file)) continue;
|
|
130
131
|
const entry = { file, home, projectDocs: null, warnings: [], diagnostics: [], hasProjectDocs: false };
|
|
131
132
|
let manifest;
|
|
132
133
|
try {
|
|
133
|
-
|
|
134
|
+
if (captured && captured.presence !== 'present') throw new Error('unreadable source');
|
|
135
|
+
manifest = JSON.parse(captured ? captured.bytes.toString('utf8') : fs.readFileSync(file, 'utf8'));
|
|
134
136
|
} catch {
|
|
135
137
|
entry.diagnostics.push({
|
|
136
138
|
code: 'invalid-host-config',
|
|
@@ -349,16 +351,18 @@ function configSource(workspaceRoot, file) {
|
|
|
349
351
|
return relativePath(workspaceRoot, file);
|
|
350
352
|
}
|
|
351
353
|
|
|
352
|
-
function
|
|
354
|
+
function resolveDocsConfigSelection(workspaceRoot, options, readSource) {
|
|
353
355
|
const resolvedRoot = workspaceRoot || getWorkspaceRoot();
|
|
354
356
|
if (!resolvedRoot) throw new Error('cannot resolve project docs outside a git workspace; pass a workspace root explicitly');
|
|
355
357
|
const root = path.resolve(resolvedRoot);
|
|
356
358
|
const projectFile = projectDocsConfigPath(root);
|
|
357
|
-
|
|
359
|
+
const capturedProject = readSource(projectFile);
|
|
360
|
+
if (capturedProject.presence !== 'absent') {
|
|
358
361
|
const source = configSource(root, projectFile);
|
|
359
362
|
let config;
|
|
360
363
|
try {
|
|
361
|
-
|
|
364
|
+
if (capturedProject.presence !== 'present') throw new Error('unreadable source');
|
|
365
|
+
config = JSON.parse(capturedProject.bytes.toString('utf8'));
|
|
362
366
|
} catch {
|
|
363
367
|
return {
|
|
364
368
|
status: 'invalid',
|
|
@@ -376,7 +380,7 @@ function resolveDocsConfig(workspaceRoot, options = {}) {
|
|
|
376
380
|
return { status: 'invalid', sources: [source], config: null, warnings, diagnostics };
|
|
377
381
|
}
|
|
378
382
|
|
|
379
|
-
const hosts = inspectHostProjectDocs(root);
|
|
383
|
+
const hosts = inspectHostProjectDocs(root, readSource);
|
|
380
384
|
const hostDiagnostics = hosts.flatMap(entry => entry.diagnostics);
|
|
381
385
|
const hostWarnings = hosts.flatMap(entry => entry.warnings);
|
|
382
386
|
const validHosts = hosts.filter(entry => entry.projectDocs);
|
|
@@ -393,7 +397,7 @@ function resolveDocsConfig(workspaceRoot, options = {}) {
|
|
|
393
397
|
return { status: 'project', sources: [source], config, warnings: [...warnings, ...hostWarnings], diagnostics: [...diagnostics, ...hostDiagnostics] };
|
|
394
398
|
}
|
|
395
399
|
|
|
396
|
-
const hosts = inspectHostProjectDocs(root);
|
|
400
|
+
const hosts = inspectHostProjectDocs(root, readSource);
|
|
397
401
|
const hostDiagnostics = hosts.flatMap(entry => entry.diagnostics);
|
|
398
402
|
const hostWarnings = hosts.flatMap(entry => entry.warnings);
|
|
399
403
|
const activeHome = normalizedHostHome(options.activeHost);
|
|
@@ -457,6 +461,35 @@ function resolveDocsConfig(workspaceRoot, options = {}) {
|
|
|
457
461
|
};
|
|
458
462
|
}
|
|
459
463
|
|
|
464
|
+
function resolveDocsConfigCaptured(workspaceRoot, options = {}) {
|
|
465
|
+
const resolvedRoot = workspaceRoot || getWorkspaceRoot();
|
|
466
|
+
if (!resolvedRoot) throw new Error('cannot resolve project docs outside a git workspace; pass a workspace root explicitly');
|
|
467
|
+
const root = path.resolve(resolvedRoot);
|
|
468
|
+
const records = new Map();
|
|
469
|
+
const readSource = file => {
|
|
470
|
+
const key = configSource(root, file);
|
|
471
|
+
if (!records.has(key)) {
|
|
472
|
+
let bytes = Buffer.alloc(0);
|
|
473
|
+
let presence = 'present';
|
|
474
|
+
try { bytes = Buffer.from(fs.readFileSync(file)); }
|
|
475
|
+
catch (error) { presence = error.code === 'ENOENT' ? 'absent' : 'unreadable'; }
|
|
476
|
+
records.set(key, { path: key, presence, bytes, digest: crypto.createHash('sha256').update(bytes).digest('hex') });
|
|
477
|
+
}
|
|
478
|
+
return records.get(key);
|
|
479
|
+
};
|
|
480
|
+
const resolution = resolveDocsConfigSelection(root, options, readSource);
|
|
481
|
+
let activeHost = null;
|
|
482
|
+
try { activeHost = JSON.parse(JSON.stringify(options.activeHost)); } catch { /* no serializable host context */ }
|
|
483
|
+
const sources = [...records.values()].sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
|
|
484
|
+
const selectionInputs = sources.map(({ path: sourcePath, presence }) => ({ path: sourcePath, presence }));
|
|
485
|
+
selectionInputs.push({ status: resolution.status, sources: [...resolution.sources], activeHost, config: resolution.config });
|
|
486
|
+
return { resolution, capture: { activeHost, sources, selectionInputs } };
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
function resolveDocsConfig(workspaceRoot, options = {}) {
|
|
490
|
+
return resolveDocsConfigCaptured(workspaceRoot, options).resolution;
|
|
491
|
+
}
|
|
492
|
+
|
|
460
493
|
function cleanConfiguredPath(value) {
|
|
461
494
|
if (typeof value !== 'string') return null;
|
|
462
495
|
const trimmed = value.trim();
|
|
@@ -769,6 +802,7 @@ module.exports = {
|
|
|
769
802
|
getRepoManifestHomes,
|
|
770
803
|
readProjectDocs,
|
|
771
804
|
resolveDocsConfig,
|
|
805
|
+
resolveDocsConfigCaptured,
|
|
772
806
|
validateDocsConfig,
|
|
773
807
|
normalizeHostProjectDocs,
|
|
774
808
|
parseContextMap,
|
package/zoom-out/SKILL.md
CHANGED
|
@@ -4,7 +4,7 @@ description: "Reflect-first circuit breaker - after 3 failures, stop edits, rebu
|
|
|
4
4
|
license: Apache-2.0
|
|
5
5
|
metadata:
|
|
6
6
|
author: Miya Daniel
|
|
7
|
-
version: 0.
|
|
7
|
+
version: 0.40.0
|
|
8
8
|
---
|
|
9
9
|
|
|
10
10
|
# Zoom Out (Circuit Breaker)
|
|
@@ -15,7 +15,7 @@ Stop repeated failures, rebuild the facts, and choose a safe next step.
|
|
|
15
15
|
|
|
16
16
|
| Component | Specification |
|
|
17
17
|
| :--- | :--- |
|
|
18
|
-
| **Trigger / Input** | Three same-signature failures or an explicit loop/rethink request. |
|
|
18
|
+
| **Trigger / Input** | Three same-signature failures, a repair loop, or an explicit loop/rethink request. |
|
|
19
19
|
| **Expected Output** | Fact-checked report ending in `RESUME` or `ESCALATE`. |
|
|
20
20
|
| **State Mutations** | Writes the session `zoom-out-report.md`; reset may clear breaker state. |
|
|
21
21
|
| **Enforcement Gate** | `<skills-repo-root>/hooks/scripts/rule-of-3.js` plus a valid report; a later three-failure cycle requests another reflection. |
|
|
@@ -25,12 +25,13 @@ Stop repeated failures, rebuild the facts, and choose a safe next step.
|
|
|
25
25
|
1. After three same-signature failures, stop edits and do not ask the user yet.
|
|
26
26
|
2. Use read-only tools to restate the goal and check files, configuration, and logs.
|
|
27
27
|
3. Fill `<this-skill-dir>/templates/zoom-out-report.template.md` and end with `RESUME` or `ESCALATE`.
|
|
28
|
-
4. Resume only on an untried path; escalate genuine user decisions with options.
|
|
28
|
+
4. Resume only on an untried path; escalate genuine user decisions with options. Repair loop: inventory sites first.
|
|
29
29
|
5. If three more matching failures occur, run another zoom-out cycle. `npm run harness:reset` is only an optional manual state clear; record the insight with `self-evolve`.
|
|
30
30
|
|
|
31
31
|
## USE FOR:
|
|
32
32
|
- "you are stuck in a loop"
|
|
33
33
|
- "the same error keeps failing"
|
|
34
|
+
- "every round finds a new edge case"
|
|
34
35
|
- "rethink your assumptions"
|
|
35
36
|
|
|
36
37
|
## DO NOT USE FOR:
|
|
@@ -27,6 +27,13 @@ flowchart TD
|
|
|
27
27
|
## 1. Triggers
|
|
28
28
|
- **Rule of 3 (Repeated Failures)**: Attempting to fix the same error or test failure 3 times without progress.
|
|
29
29
|
- **Divergence**: Fixing one bug repeatedly introduces new secondary errors.
|
|
30
|
+
- **Repair loop (feature level)**: Two consecutive review or fix rounds on the same feature each surface new defects in the same decision class (for example "is this the trusted checker?"), even though every command succeeded.
|
|
31
|
+
- The Rule of 3 hook cannot see this. It counts same-signature command failures in one session. Successful review findings do not increment it, and unrelated successes can leave an existing count in place. New sessions and different failure signatures do not accumulate a feature's review history.
|
|
32
|
+
- The signal comes from review history: prior findings and their dispositions, the round count per class in an error ledger, or the reviewer noticing the pattern. It is a prompt to reflect, not a lock. The hook gate in the skill contract applies only to the three-failure trigger.
|
|
33
|
+
- "Same decision class" means the same acceptance decision under the same trust assumptions, possibly at different sites. "Same directory" or "validation" is too broad. Count a repeated or renamed finding once, and treat missing history as unknown, not zero.
|
|
34
|
+
- Phase 2 here means: list every finding so far by decision class, state the acceptance clause each violates, and inventory every site (callers, state readers, Stop consumers) that makes the same decision. Findings that map to no acceptance clause stay `unresolved` for the owner instead of becoming new fixes.
|
|
35
|
+
- RESUME by using the inventory to choose the smallest justified correction (which may be one shared fix, or no code change), then re-trace one normal end-to-end acceptance path. Unresolved findings need scope adjudication, not speculative repairs.
|
|
36
|
+
- A one-shot reviewer cannot see the previous round on its own. The packet carries the current acceptance anchor, a link to the previous comparable report with its revision, the prior finding IDs and dispositions, and the fix made since.
|
|
30
37
|
- **Goal Drift**: Execution strays far from the initial task objective.
|
|
31
38
|
- **User Instruction**: The user requests a step back ("zoom out", "step back", "stop and think").
|
|
32
39
|
|
|
@@ -3,12 +3,14 @@
|
|
|
3
3
|
|
|
4
4
|
## Failed Attempts
|
|
5
5
|
<attempt → underlying assumption → observed outcome>
|
|
6
|
-
**Failure Category:** <syntax|environment|test|timeout|permission|dependency|unknown>
|
|
6
|
+
**Failure Category:** <syntax|environment|test|timeout|permission|dependency|repair-loop|unknown>
|
|
7
|
+
**Repair-loop rounds (repair loop only):** <round → new finding → decision class → violated acceptance clause or `unresolved`>
|
|
7
8
|
|
|
8
9
|
## Verified Facts
|
|
9
10
|
<facts re-checked in Phase 2 with file paths>
|
|
10
11
|
**Files Checked:** <list at least 3 related files you actually read>
|
|
11
|
-
**Error Message Verified:** <copy the exact error message from the last failure>
|
|
12
|
+
**Error Message Verified:** <copy the exact error message from the last failure; for a repair loop with no error, write `none` and cite the latest finding instead>
|
|
13
|
+
**Sites Inventoried (repair loop only):** <every site making the same decision, including unchanged callers and consumers>
|
|
12
14
|
|
|
13
15
|
## Diagnosis
|
|
14
16
|
<comprehensive explanation of root cause>
|