@chrono-meta/fh-gate 1.0.3 → 1.2.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/agents/challenger.md +169 -0
- package/AGENTS.md +160 -0
- package/CATALOG.md +256 -0
- package/CHEATSHEET.md +367 -0
- package/CLAUDE.md +331 -0
- package/CONTRIBUTING.md +198 -0
- package/LICENSE +21 -0
- package/README.md +131 -418
- package/bin/fh-goal.js +9 -0
- package/bin/fh-run.js +9 -0
- package/docs/banner.png +0 -0
- package/docs/codex-compat.md +123 -0
- package/docs/pillars.svg +70 -0
- package/knowledge/shared/harness-core/fh_integration_contract.md +48 -29
- package/package.json +31 -6
- package/plugins/fh-commons/README.md +37 -0
- package/plugins/fh-commons/agents/quench-challenger.md +373 -0
- package/plugins/fh-commons/skills/convergence-loop/SKILL.md +155 -0
- package/plugins/fh-commons/skills/deliberation/SKILL.md +288 -0
- package/plugins/fh-commons/skills/mcp-circuit-breaker/SKILL.md +196 -0
- package/plugins/fh-commons/skills/token-budget-gate/SKILL.md +175 -0
- package/plugins/fh-meta/agents/fact-checker.md +121 -0
- package/plugins/fh-meta/agents/hub-persona-auditor.md +109 -0
- package/plugins/fh-meta/agents/persona-innovator.md +195 -0
- package/plugins/fh-meta/skills/agent-composer/SKILL.md +461 -0
- package/plugins/fh-meta/skills/agent-composer/SKILL_detail.md +464 -0
- package/plugins/fh-meta/skills/apex-review/SKILL.md +185 -0
- package/plugins/fh-meta/skills/asset-placement-gate/SKILL.md +135 -0
- package/plugins/fh-meta/skills/contention-layer/SKILL.md +127 -0
- package/plugins/fh-meta/skills/context-bridge-dispatch/SKILL.md +30 -0
- package/plugins/fh-meta/skills/context-bridge-dispatch/SKILL_detail.md +144 -0
- package/plugins/fh-meta/skills/context-doctor/SKILL.md +341 -0
- package/plugins/fh-meta/skills/cross-ecosystem-synergy-detection/SKILL.md +202 -0
- package/plugins/fh-meta/skills/deep-clarify/SKILL.md +144 -0
- package/plugins/fh-meta/skills/edit-manifest/SKILL.md +210 -0
- package/plugins/fh-meta/skills/field-harvest/SKILL.md +384 -0
- package/plugins/fh-meta/skills/frontier-digest/SKILL.md +272 -0
- package/plugins/fh-meta/skills/goal-quench/SKILL.md +509 -0
- package/plugins/fh-meta/skills/harness-doctor/SKILL.md +277 -0
- package/plugins/fh-meta/skills/harness-doctor/SKILL_detail.md +484 -0
- package/plugins/fh-meta/skills/harvest-loop/SKILL.md +231 -0
- package/plugins/fh-meta/skills/harvest-loop/SKILL_detail.md +201 -0
- package/plugins/fh-meta/skills/hub-cc-pr-reviewer/SKILL.md +129 -0
- package/plugins/fh-meta/skills/hub-cc-pr-reviewer/SKILL_detail.md +158 -0
- package/plugins/fh-meta/skills/install-doctor/SKILL.md +207 -0
- package/plugins/fh-meta/skills/install-wizard/SKILL.md +613 -0
- package/plugins/fh-meta/skills/marketplace-gate/SKILL.md +193 -0
- package/plugins/fh-meta/skills/memory-hygiene/SKILL.md +143 -0
- package/plugins/fh-meta/skills/meta-prompt-builder/SKILL.md +167 -0
- package/plugins/fh-meta/skills/meta-prompt-builder/SKILL_detail.md +37 -0
- package/plugins/fh-meta/skills/pipeline-conductor/SKILL.md +430 -0
- package/plugins/fh-meta/skills/plugin-recommender/SKILL.md +221 -0
- package/plugins/fh-meta/skills/plugin-recommender/SKILL_detail.md +220 -0
- package/plugins/fh-meta/skills/prompt-regression/SKILL.md +178 -0
- package/plugins/fh-meta/skills/public-surface-audit/SKILL.md +224 -0
- package/plugins/fh-meta/skills/return-path-gate/SKILL.md +257 -0
- package/plugins/fh-meta/skills/self-marketing-lint/SKILL.md +129 -0
- package/plugins/fh-meta/skills/sim-conductor/SKILL.md +364 -0
- package/plugins/fh-meta/skills/sim-conductor/SKILL_detail.md +337 -0
- package/plugins/fh-meta/skills/skill-splitter/SKILL.md +126 -0
- package/plugins/fh-meta/skills/skill-splitter/SKILL_detail.md +185 -0
- package/plugins/fh-meta/skills/source-grounding-audit/SKILL.md +230 -0
- package/plugins/fh-meta/skills/source-grounding-audit/SKILL_detail.md +182 -0
- package/plugins/fh-meta/skills/steel-quench/SKILL.md +226 -0
- package/plugins/fh-meta/skills/steel-quench/SKILL_detail.md +453 -0
- package/plugins/fh-meta/skills/verify-bidirectional/SKILL.md +238 -0
- package/scripts/fh-gate.sh +175 -40
- package/scripts/fh-goal.sh +182 -0
- package/scripts/fh-run.sh +269 -0
|
@@ -0,0 +1,484 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: harness-doctor-detail
|
|
3
|
+
description: Detail file for harness-doctor — bash scripts for Steps 1~6 (L1~L4 diagnostics), L5 pattern analysis bash, Step 11 PR consistency check bash. Load when running diagnostic commands.
|
|
4
|
+
load: on-demand
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# harness-doctor — Detail Reference
|
|
8
|
+
|
|
9
|
+
> Load when running diagnostic commands. SKILL.md contains layer descriptions, verdict tables, Done When, and trigger phrases.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## §Step-1-3 — Bash Scripts for Steps 1~5 (L1~L3 Diagnostics)
|
|
14
|
+
|
|
15
|
+
### Step 1. Confirm Diagnostic Target
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# Check current cwd harness file structure
|
|
19
|
+
ls -la .claude/ 2>/dev/null || echo "NO .claude DIR"
|
|
20
|
+
ls -la CLAUDE.md .claudeignore 2>/dev/null
|
|
21
|
+
ls .claude/rules/ 2>/dev/null
|
|
22
|
+
ls .claude/agents/ 2>/dev/null
|
|
23
|
+
|
|
24
|
+
# tracks/ present = FH or hub environment
|
|
25
|
+
ls -d tracks/ knowledge/ plugins/ 2>/dev/null
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Step 2. L1 — Structural Completeness
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
for f in CLAUDE.md .claudeignore; do
|
|
32
|
+
[ -f "$f" ] && echo "OK: $f" || echo "MISSING: $f"
|
|
33
|
+
done
|
|
34
|
+
[ -d ".claude" ] && echo "OK: .claude/" || echo "MISSING: .claude/"
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Step 3. L2 — Complexity Diagnosis
|
|
38
|
+
|
|
39
|
+
#### 3-1. CLAUDE.md Line Count
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
wc -l CLAUDE.md 2>/dev/null
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
#### 3-2. Rules File Unreferenced Detection
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
ls .claude/rules/*.md 2>/dev/null
|
|
49
|
+
|
|
50
|
+
find .claude/rules -maxdepth 1 -name '*.md' 2>/dev/null | while read -r f; do
|
|
51
|
+
fname=$(basename "$f")
|
|
52
|
+
grep -l "$fname" CLAUDE.md 2>/dev/null \
|
|
53
|
+
&& echo "REFERENCED: $fname" \
|
|
54
|
+
|| echo "UNREFERENCED: $fname"
|
|
55
|
+
done
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
#### 3-3. Duplicate Section Detection
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
grep -c "^##" CLAUDE.md 2>/dev/null
|
|
62
|
+
# 15+ sections = S-tier warning
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
#### 3-4. Periodic Skill Activity Check
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
# Check date of last weekly_audit file
|
|
69
|
+
latest_audit=$(ls -1t tracks/_audit/weekly_audit_*.md 2>/dev/null | head -1)
|
|
70
|
+
if [ -z "$latest_audit" ]; then
|
|
71
|
+
echo "MISSING: no weekly_audit files"
|
|
72
|
+
else
|
|
73
|
+
days_ago=$(( ( $(date +%s) - $(stat -f %m "$latest_audit" 2>/dev/null || stat -c %Y "$latest_audit") ) / 86400 ))
|
|
74
|
+
echo "LAST_AUDIT: $latest_audit (${days_ago} days ago)"
|
|
75
|
+
[ "$days_ago" -gt 30 ] && echo "OVERDUE_M: 30+ days without running" \
|
|
76
|
+
|| { [ "$days_ago" -gt 14 ] && echo "OVERDUE_S: 14+ days without running" || echo "OK: cycle normal"; }
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
# Check last sim-conductor result file
|
|
80
|
+
latest_sim=$(ls -1t tracks/_meta/sim_*.md 2>/dev/null | head -1)
|
|
81
|
+
[ -n "$latest_sim" ] && echo "LAST_SIM: $latest_sim" || echo "INFO: no sim record (optional)"
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Step 4. L3 — Drift Diagnosis
|
|
85
|
+
|
|
86
|
+
#### 4-1. Broken File References
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
grep -oE '`[./][^`]+`' CLAUDE.md 2>/dev/null | tr -d '`' \
|
|
90
|
+
| grep -vE '\*|[[:space:]]|^/[^/]+$' \
|
|
91
|
+
| sort -u | while read p; do
|
|
92
|
+
[ -e "$p" ] && echo "OK: $p" || echo "BROKEN: $p"
|
|
93
|
+
done
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
#### 4-2. Stale Rules Detection
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
find .claude/rules/ -name "*.md" -mtime +90 2>/dev/null \
|
|
100
|
+
&& echo "STALE: 90+ day unmodified rules files exist" \
|
|
101
|
+
|| echo "OK: no stale"
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
#### 4-3. settings.json Validity
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
[ -f ".claude/settings.json" ] \
|
|
108
|
+
&& python3 -c "import json,sys; json.load(open('.claude/settings.json'))" 2>/dev/null \
|
|
109
|
+
&& echo "OK: settings.json valid" \
|
|
110
|
+
|| echo "BROKEN: settings.json syntax error"
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
#### 4-4. Hook Divergence Diagnosis
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
if [ -f ".claude/settings.json" ]; then
|
|
117
|
+
hook_count=$(python3 -c "
|
|
118
|
+
import json, sys
|
|
119
|
+
try:
|
|
120
|
+
d = json.load(open('.claude/settings.json'))
|
|
121
|
+
hooks = d.get('hooks', [])
|
|
122
|
+
print(len(hooks))
|
|
123
|
+
except:
|
|
124
|
+
print(0)
|
|
125
|
+
" 2>/dev/null || echo 0)
|
|
126
|
+
if [ "$hook_count" -gt 0 ]; then
|
|
127
|
+
echo "HOOKS_FOUND: ${hook_count} hooks detected in settings.json"
|
|
128
|
+
python3 -c "
|
|
129
|
+
import json
|
|
130
|
+
d = json.load(open('.claude/settings.json'))
|
|
131
|
+
for h in d.get('hooks', []):
|
|
132
|
+
event = h.get('event', 'unknown')
|
|
133
|
+
cmds = [c.get('command','') for m in h.get('matchers',[{}]) for c in m.get('hooks',[])]
|
|
134
|
+
print(f' HOOK: event={event} | commands={cmds[:2]}')
|
|
135
|
+
" 2>/dev/null
|
|
136
|
+
echo "AGENT_VIEW_WARN: above hooks do NOT fire in Agent View (claude agents)"
|
|
137
|
+
echo " Prescription: replace hook-dependent behavior with explicit skills"
|
|
138
|
+
else
|
|
139
|
+
echo "OK: no hooks configured"
|
|
140
|
+
fi
|
|
141
|
+
else
|
|
142
|
+
echo "INFO: no settings.json — hook divergence diagnosis skip"
|
|
143
|
+
fi
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Step 5. L4 — Connection Diagnosis (FH only)
|
|
147
|
+
|
|
148
|
+
#### 5-1. Field Project Tracks Freshness
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
for d in tracks/*/; do
|
|
152
|
+
last=$(find "$d" -name "*.md" -newer "tracks/.gitkeep" 2>/dev/null | wc -l)
|
|
153
|
+
echo "$d: $last files modified recently"
|
|
154
|
+
done
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
#### 5-2. CATALOG.md Open Item Count
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
awk '/^### /{count++} count<=5{print}' CATALOG.md 2>/dev/null | grep -c "^- Open:" || echo "0"
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
> Do not use `grep -c "^- Open:" CATALOG.md` — returns hundreds as false positives counting entire history.
|
|
164
|
+
|
|
165
|
+
#### 5-3. Field Project CLAUDE.md Existence
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
grep -oE '`~/[^`]+`' .claude/memory/reference_field_projects.md 2>/dev/null \
|
|
169
|
+
| tr -d '`' | sed "s|~|$HOME|g" | while read p; do
|
|
170
|
+
[ -f "$p/CLAUDE.md" ] && echo "OK: $p" || echo "MISSING CLAUDE.md: $p"
|
|
171
|
+
done
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## §L5-Detail — Bash Scripts for L5-A, L5-B, L5-C
|
|
177
|
+
|
|
178
|
+
### L5-A Skill Activity (bash)
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
recent_sessions=$(find tracks/ -name "session_*.md" -mtime -30 2>/dev/null)
|
|
182
|
+
if [ -z "$recent_sessions" ]; then
|
|
183
|
+
echo "L5-A SKIP: no session records — re-diagnose after 30 days"
|
|
184
|
+
else
|
|
185
|
+
installed_skills=$(ls plugins/fh-meta/skills/ 2>/dev/null)
|
|
186
|
+
|
|
187
|
+
for skill in $installed_skills; do
|
|
188
|
+
count=0
|
|
189
|
+
for f in $recent_sessions; do
|
|
190
|
+
grep -li "$skill\|/$skill" "$f" 2>/dev/null && ((count++)) || true
|
|
191
|
+
done
|
|
192
|
+
if [ "$count" -eq 0 ]; then
|
|
193
|
+
sessions_90d=$(find tracks/ -name "session_*.md" -mtime -90 2>/dev/null)
|
|
194
|
+
count_90d=0
|
|
195
|
+
for f in $sessions_90d; do
|
|
196
|
+
grep -li "$skill\|/$skill" "$f" 2>/dev/null && ((count_90d++)) || true
|
|
197
|
+
done
|
|
198
|
+
if [ "$count_90d" -eq 0 ]; then
|
|
199
|
+
echo "INACTIVE_90D: $skill (no call record in 90 days)"
|
|
200
|
+
else
|
|
201
|
+
echo "INACTIVE_30D: $skill (no call record in last 30 days)"
|
|
202
|
+
fi
|
|
203
|
+
elif [ "$count" -lt 2 ]; then
|
|
204
|
+
echo "LOW_ACTIVE: $skill (${count} times)"
|
|
205
|
+
else
|
|
206
|
+
echo "ACTIVE: $skill (${count} times)"
|
|
207
|
+
fi
|
|
208
|
+
done
|
|
209
|
+
fi
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### L5-B Call Context Appropriateness (bash)
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
recent_sessions=$(find tracks/ -name "session_*.md" -mtime -30 2>/dev/null)
|
|
216
|
+
[ -z "$recent_sessions" ] && echo "L5-B SKIP: no session records" && exit 0
|
|
217
|
+
|
|
218
|
+
# hub-persona-auditor misuse: code PR or internal refactoring context
|
|
219
|
+
for f in $recent_sessions; do
|
|
220
|
+
if grep -q "hub-persona-auditor" "$f" 2>/dev/null; then
|
|
221
|
+
context=$(grep -n "hub-persona-auditor" "$f" | head -3)
|
|
222
|
+
echo "$context" | while IFS=: read linenum rest; do
|
|
223
|
+
snippet=$(sed -n "$((linenum-3)),$((linenum+3))p" "$f" 2>/dev/null)
|
|
224
|
+
if echo "$snippet" | grep -qiE "code review|PR review|refactoring"; then
|
|
225
|
+
echo "L5-B MISUSE (suspected): hub-persona-auditor @ $f:$linenum — code PR context (false positive possible)"
|
|
226
|
+
fi
|
|
227
|
+
done
|
|
228
|
+
fi
|
|
229
|
+
done
|
|
230
|
+
|
|
231
|
+
# sim-conductor misuse: first run without onboarding context
|
|
232
|
+
for f in $recent_sessions; do
|
|
233
|
+
if grep -q "sim-conductor" "$f" 2>/dev/null; then
|
|
234
|
+
context=$(grep -n "sim-conductor" "$f" | head -3)
|
|
235
|
+
echo "$context" | while IFS=: read linenum rest; do
|
|
236
|
+
snippet=$(sed -n "$((linenum-3)),$((linenum+3))p" "$f" 2>/dev/null)
|
|
237
|
+
if echo "$snippet" | grep -qiE "first time|how do I|not sure how"; then
|
|
238
|
+
echo "L5-B MISUSE (suspected): sim-conductor @ $f:$linenum — first run / no onboarding context (false positive possible)"
|
|
239
|
+
fi
|
|
240
|
+
done
|
|
241
|
+
fi
|
|
242
|
+
done
|
|
243
|
+
|
|
244
|
+
# harness-doctor self-loop misuse
|
|
245
|
+
for f in $recent_sessions; do
|
|
246
|
+
count=$(grep -c "harness-doctor" "$f" 2>/dev/null || echo 0)
|
|
247
|
+
if [ "$count" -gt 2 ]; then
|
|
248
|
+
echo "L5-B MISUSE (suspected): harness-doctor @ $f — self-loop suspected (${count} mentions in same session)"
|
|
249
|
+
fi
|
|
250
|
+
done
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### L5-C Effect Metrics (bash)
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
# E1: CLAUDE.md line count change
|
|
257
|
+
current_lines=$(wc -l < CLAUDE.md 2>/dev/null || echo 0)
|
|
258
|
+
past_lines=$(git show "HEAD@{30 days ago}:CLAUDE.md" 2>/dev/null | wc -l || echo "N/A")
|
|
259
|
+
if [ "$past_lines" != "N/A" ] && [ "$past_lines" -gt 0 ]; then
|
|
260
|
+
delta=$((current_lines - past_lines))
|
|
261
|
+
if [ "$delta" -lt 0 ]; then
|
|
262
|
+
echo "E1_OK: CLAUDE.md ${delta} lines reduced"
|
|
263
|
+
elif [ "$delta" -gt 50 ]; then
|
|
264
|
+
echo "E1_WARN: CLAUDE.md +${delta} lines increased"
|
|
265
|
+
else
|
|
266
|
+
echo "E1_STABLE: CLAUDE.md ±${delta} lines"
|
|
267
|
+
fi
|
|
268
|
+
else
|
|
269
|
+
echo "E1_SKIP: git history < 30 days or no CLAUDE.md"
|
|
270
|
+
fi
|
|
271
|
+
|
|
272
|
+
# E2: Skill complexity ratio
|
|
273
|
+
total_lines=$(cat plugins/fh-meta/skills/*/SKILL.md plugins/fh-commons/skills/*/SKILL.md 2>/dev/null | wc -l | tr -d ' ')
|
|
274
|
+
skill_count=$(ls -d plugins/fh-meta/skills/*/ plugins/fh-commons/skills/*/ 2>/dev/null | wc -l | tr -d ' ')
|
|
275
|
+
if [ "$skill_count" -gt 0 ]; then
|
|
276
|
+
ratio=$((total_lines / skill_count))
|
|
277
|
+
if [ "$ratio" -le 100 ]; then echo "E2_OK: avg ${ratio} lines/skill (healthy)"
|
|
278
|
+
elif [ "$ratio" -le 200 ]; then echo "E2_WARN: avg ${ratio} lines/skill (caution)"
|
|
279
|
+
else echo "E2_FAIL: avg ${ratio} lines/skill (overloaded — separation or compression needed)"
|
|
280
|
+
fi
|
|
281
|
+
fi
|
|
282
|
+
|
|
283
|
+
# E3: CATALOG.md Open item consumption rate
|
|
284
|
+
current_open=$(awk '/^### /{count++} count<=5{print}' CATALOG.md 2>/dev/null | grep -c "^- Open:" || echo 0)
|
|
285
|
+
past_open=$(git show "HEAD@{30 days ago}:CATALOG.md" 2>/dev/null \
|
|
286
|
+
| awk '/^### /{count++} count<=5{print}' | grep -c "^- Open:" || echo "N/A")
|
|
287
|
+
if [ "$past_open" != "N/A" ]; then
|
|
288
|
+
consumed=$((past_open - current_open))
|
|
289
|
+
echo "E3: Open items consumed ${consumed} (30 days ago: ${past_open} → now: ${current_open})"
|
|
290
|
+
else
|
|
291
|
+
echo "E3_SKIP: git history < 30 days"
|
|
292
|
+
fi
|
|
293
|
+
|
|
294
|
+
# E4: harvest signals
|
|
295
|
+
signal_dir=tracks/_meta
|
|
296
|
+
signal_count=$(find "$signal_dir" -name "fh_signal_*.md" -newer "$(date -v-30d +%Y-%m-%d 2>/dev/null || date -d '30 days ago' +%Y-%m-%d)" 2>/dev/null | wc -l | tr -d ' ')
|
|
297
|
+
echo "E4: harvest signals in last 30 days: ${signal_count} (target: ≥3)"
|
|
298
|
+
|
|
299
|
+
# E5: SKILL.md last change
|
|
300
|
+
last_skill_change=$(git log -1 --format="%ad (%ar)" -- "plugins/fh-meta/skills/*/SKILL.md" 2>/dev/null || echo "N/A")
|
|
301
|
+
echo "E5: SKILL.md last change — $last_skill_change"
|
|
302
|
+
|
|
303
|
+
# E6: Cold Audit last execution
|
|
304
|
+
last_audit=$(find "$signal_dir" -name "*cold_audit*" -o -name "*audit*" 2>/dev/null | xargs ls -t 2>/dev/null | head -1)
|
|
305
|
+
if [ -n "$last_audit" ]; then
|
|
306
|
+
last_date=$(stat -f "%Sm" -t "%Y-%m-%d" "$last_audit" 2>/dev/null || stat -c "%y" "$last_audit" 2>/dev/null | cut -d' ' -f1)
|
|
307
|
+
echo "E6: last cold audit — ${last_date}"
|
|
308
|
+
else
|
|
309
|
+
echo "E6_WARN: no cold audit history (30-day SLA recommended)"
|
|
310
|
+
fi
|
|
311
|
+
|
|
312
|
+
# E7: Evolution-loop blindness
|
|
313
|
+
manifest=tracks/_meta/edit_manifest.yaml
|
|
314
|
+
recent_asset_edits=$(git log --since="14 days ago" --name-only --pretty=format: 2>/dev/null \
|
|
315
|
+
| grep -E "SKILL\.md|\.claude/rules/|^CLAUDE\.md" | sort -u | wc -l | tr -d ' ')
|
|
316
|
+
if [ ! -f "$manifest" ]; then
|
|
317
|
+
[ "$recent_asset_edits" -gt 0 ] \
|
|
318
|
+
&& echo "E7_WARN: ${recent_asset_edits} asset edit(s) in 14d but no edit_manifest.yaml" \
|
|
319
|
+
|| echo "E7: no recent asset edits"
|
|
320
|
+
else
|
|
321
|
+
manifest_recent=$(grep -c "$(date +%Y-%m)" "$manifest" 2>/dev/null || echo 0)
|
|
322
|
+
[ "$recent_asset_edits" -gt 0 ] && [ "$manifest_recent" -eq 0 ] \
|
|
323
|
+
&& echo "E7_WARN: asset edits exist but no manifest entry this month" \
|
|
324
|
+
|| echo "E7_OK: edit_manifest.yaml present with recent entries"
|
|
325
|
+
fi
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
## §Step11 — PR Change Consistency Check Bash Scripts
|
|
331
|
+
|
|
332
|
+
### 11-1. Detect Changed Files
|
|
333
|
+
|
|
334
|
+
```bash
|
|
335
|
+
changed=$(git diff main..HEAD --name-only 2>/dev/null)
|
|
336
|
+
[ -z "$changed" ] && changed=$(git diff --cached --name-only 2>/dev/null)
|
|
337
|
+
[ -z "$changed" ] && echo "PR_CHECK: no changes detected vs main — skip" && return 0
|
|
338
|
+
echo "=== Changed files ($(echo "$changed" | wc -l | tr -d ' ') total) ==="
|
|
339
|
+
echo "$changed"
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### 11-2A. SKILL.md Changes → Count Drift + README + CATALOG
|
|
343
|
+
|
|
344
|
+
```bash
|
|
345
|
+
skills_changed=$(echo "$changed" | grep "skills/.*/SKILL\.md" || true)
|
|
346
|
+
if [ -n "$skills_changed" ]; then
|
|
347
|
+
cat > /tmp/_fh_count.py <<'PYEOF'
|
|
348
|
+
import json, glob, os, re
|
|
349
|
+
def claimed_count(desc):
|
|
350
|
+
m = re.search(r'(\d+)\s*skills', desc)
|
|
351
|
+
return int(m.group(1)) if m else None
|
|
352
|
+
for src in sorted(glob.glob('plugins/*')):
|
|
353
|
+
if not os.path.isdir(os.path.join(src, 'skills')):
|
|
354
|
+
continue
|
|
355
|
+
pname = os.path.basename(src)
|
|
356
|
+
actual = len(glob.glob(os.path.join(src, 'skills', '*/')))
|
|
357
|
+
pj = os.path.join(src, '.claude-plugin', 'plugin.json')
|
|
358
|
+
if os.path.exists(pj):
|
|
359
|
+
c = claimed_count(json.load(open(pj)).get('description', ''))
|
|
360
|
+
if c is not None and c != actual:
|
|
361
|
+
print(f"DRIFT: {pname} plugin.json says '{c} skills' but {actual} dirs")
|
|
362
|
+
elif c is not None:
|
|
363
|
+
print(f"OK: {pname} plugin.json count {actual} matches")
|
|
364
|
+
mp = '.claude-plugin/marketplace.json'
|
|
365
|
+
if os.path.exists(mp):
|
|
366
|
+
for p in json.load(open(mp)).get('plugins', []):
|
|
367
|
+
src = p.get('source', '').lstrip('./')
|
|
368
|
+
actual = len(glob.glob(os.path.join(src, 'skills', '*/')))
|
|
369
|
+
c = claimed_count(p.get('description', ''))
|
|
370
|
+
if c is not None and c != actual:
|
|
371
|
+
print(f"DRIFT: marketplace.json[{p['name']}] says '{c} skills' but {actual} dirs")
|
|
372
|
+
PYEOF
|
|
373
|
+
python3 /tmp/_fh_count.py
|
|
374
|
+
|
|
375
|
+
echo "$skills_changed" | while read sp; do
|
|
376
|
+
sname=$(basename "$(dirname "$sp")")
|
|
377
|
+
grep -q "$sname" README.md 2>/dev/null \
|
|
378
|
+
&& echo "OK: $sname in README" \
|
|
379
|
+
|| echo "MISSING: '$sname' not in README.md"
|
|
380
|
+
grep -q "$sname" CATALOG.md 2>/dev/null \
|
|
381
|
+
&& echo "OK: $sname in CATALOG" \
|
|
382
|
+
|| echo "MISSING: '$sname' not in CATALOG.md"
|
|
383
|
+
done
|
|
384
|
+
fi
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
### 11-2B. Agent File Changes → README + agent_cards.json
|
|
388
|
+
|
|
389
|
+
```bash
|
|
390
|
+
agents_changed=$(echo "$changed" | grep -E "agents/.*\.md" || true)
|
|
391
|
+
if [ -n "$agents_changed" ]; then
|
|
392
|
+
actual_agents=$(find .claude/agents plugins/*/agents -name "*.md" 2>/dev/null | wc -l | tr -d ' ')
|
|
393
|
+
readme_agents=$(grep -oE '[0-9]+ (fh-meta \+ [0-9]+ fh-commons )?agents?' README.md 2>/dev/null | head -1 || echo "not found")
|
|
394
|
+
echo "Agent files: $actual_agents | README mentions: $readme_agents"
|
|
395
|
+
if [ -f .claude/registry/agent_cards.json ]; then
|
|
396
|
+
cards_count=$(grep -oE '"agent_count":[[:space:]]*[0-9]+' .claude/registry/agent_cards.json | grep -oE '[0-9]+')
|
|
397
|
+
canonical_agents=$(find .claude/agents plugins/fh-meta/agents plugins/fh-commons/agents -name "*.md" 2>/dev/null | wc -l | tr -d ' ')
|
|
398
|
+
[ "$cards_count" = "$canonical_agents" ] \
|
|
399
|
+
&& echo "OK: agent_cards.json count ($cards_count) matches tracked agent files" \
|
|
400
|
+
|| echo "DRIFT: agent_cards.json says $cards_count but tracked agent files total $canonical_agents — regenerate registry"
|
|
401
|
+
fi
|
|
402
|
+
fi
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
### 11-2C. knowledge/shared/ Changes → CATALOG
|
|
406
|
+
|
|
407
|
+
```bash
|
|
408
|
+
knowledge_changed=$(echo "$changed" | grep "^knowledge/" || true)
|
|
409
|
+
if [ -n "$knowledge_changed" ]; then
|
|
410
|
+
echo "$knowledge_changed" | while read kf; do
|
|
411
|
+
fname=$(basename "$kf" .md)
|
|
412
|
+
grep -q "$fname" CATALOG.md 2>/dev/null \
|
|
413
|
+
&& echo "OK: $fname in CATALOG" \
|
|
414
|
+
|| echo "MISSING: '$fname' not in CATALOG.md"
|
|
415
|
+
done
|
|
416
|
+
fi
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
### 11-2D. README.md Changed → Stale References
|
|
420
|
+
|
|
421
|
+
```bash
|
|
422
|
+
if echo "$changed" | grep -q "^README\.md$"; then
|
|
423
|
+
grep -n "chrono-code" README.md 2>/dev/null && echo "STALE: 'chrono-code' found — should be 'chrono-meta'" || true
|
|
424
|
+
actual=$(ls -d plugins/fh-meta/skills/*/ plugins/fh-commons/skills/*/ 2>/dev/null | wc -l | tr -d ' ')
|
|
425
|
+
readme_count=$(grep -oE '[0-9]+ (fh-meta[^)]+)?skills' README.md 2>/dev/null | head -1 || echo "not found")
|
|
426
|
+
echo "Actual skills: $actual | README mentions: $readme_count"
|
|
427
|
+
fi
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
### 11-2E. AGENTS.md / CLAUDE.md Changed → Cross-Reference
|
|
431
|
+
|
|
432
|
+
```bash
|
|
433
|
+
if echo "$changed" | grep -qE "^AGENTS\.md$|^CLAUDE\.md$"; then
|
|
434
|
+
if [ -f AGENTS.md ]; then
|
|
435
|
+
agents_in_file=$(grep -c "^##\? " AGENTS.md 2>/dev/null || echo "?")
|
|
436
|
+
actual_agents=$(find .claude/agents plugins/*/agents -name "*.md" 2>/dev/null | wc -l | tr -d ' ')
|
|
437
|
+
echo "AGENTS.md sections: $agents_in_file | Actual agent files: $actual_agents"
|
|
438
|
+
fi
|
|
439
|
+
fi
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
### 11-3. Step 8 — harvest-loop Integration
|
|
443
|
+
|
|
444
|
+
```bash
|
|
445
|
+
ls -1t tracks/_audit/weekly_audit_*.md 2>/dev/null | head -1
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
If latest weekly_audit exists → propose adding:
|
|
449
|
+
|
|
450
|
+
```markdown
|
|
451
|
+
### Harness Structure Check (harness-doctor)
|
|
452
|
+
- [ ] CLAUDE.md line count within threshold
|
|
453
|
+
- [ ] No broken file references
|
|
454
|
+
- [ ] Unreferenced rules files cleaned up
|
|
455
|
+
- [ ] Check tracks with no sync in 30+ days
|
|
456
|
+
- [ ] Review INACTIVE_30D skills (L5-A)
|
|
457
|
+
- [ ] Check suspected misuse patterns (L5-B)
|
|
458
|
+
- [ ] Review effect metrics E1·E3·E5 (L5-C)
|
|
459
|
+
- [ ] Hook divergence — create alternative for Agent View
|
|
460
|
+
- [ ] Harness-defect taxonomy: Context Drift · Schema Misalignment · State Degradation
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
### Step 9 — Eval-First Quantitative Gate (v0.x → v1 only)
|
|
464
|
+
|
|
465
|
+
```bash
|
|
466
|
+
latest_sims=$(find tracks/_meta/ -name "sim_*.md" 2>/dev/null | sort -r | head -5)
|
|
467
|
+
[ -z "$latest_sims" ] && echo "EVAL_SKIP: run sim-conductor 5 times first" && exit 0
|
|
468
|
+
echo "Target sim files:"; echo "$latest_sims"
|
|
469
|
+
# Manual review — aggregate correct-skill-selections / total per sim file
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
Thresholds: Tool Selection Accuracy > 0.90 · Multi-Step Coherence > 0.85 · Clarification Rate < 0.30.
|
|
473
|
+
|
|
474
|
+
### Step 10.6 — Cross-Skill Capability (syntax verification reuse)
|
|
475
|
+
|
|
476
|
+
F7 (bash -n parse) is a general-purpose syntax capability. Other skills reuse it:
|
|
477
|
+
|
|
478
|
+
| Skill | Purpose | Axis |
|
|
479
|
+
|---|---|---|
|
|
480
|
+
| harness-doctor Step 10 (this) | Regression detection — new syntax errors from change | *Backward* |
|
|
481
|
+
| steel-quench | Attack vector — "SKILL.md claims bash runs but has syntax errors" | *Adversarial* |
|
|
482
|
+
| source-grounding-audit | Phantom claim — code in docs that doesn't parse = fabricated example | *Forward* |
|
|
483
|
+
|
|
484
|
+
For shared utility: `templates/regression_guard.sh` — extract `count_bad_blocks` function or invoke with ref pair.
|