@chrono-meta/fh-gate 1.4.95 → 1.4.97
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 +2 -2
- package/AGENTS.md +18 -0
- package/CHEATSHEET.md +1 -1
- package/CLAUDE.md +11 -4
- package/README.md +19 -0
- package/knowledge/shared/harness-core/fh_detail_protocols.md +12 -0
- package/knowledge/shared/harness-core/ship_readiness_gate.md +7 -4
- package/knowledge/shared/learnings/subagent_invocations_log.yaml +113 -1
- package/package.json +10 -2
- package/plugins/fh-commons/.claude-plugin/plugin.json +1 -1
- package/plugins/fh-commons/agents/quench-challenger.md +49 -23
- package/plugins/fh-commons/skills/convergence-loop/SKILL.md +14 -0
- package/plugins/fh-commons/skills/deliberation/SKILL.md +14 -0
- package/plugins/fh-commons/skills/mcp-circuit-breaker/SKILL.md +10 -1
- package/plugins/fh-meta/.claude-plugin/plugin.json +1 -1
- package/plugins/fh-meta/CHANGELOG.md +36 -0
- package/plugins/fh-meta/agents/beginner.md +4 -1
- package/plugins/fh-meta/agents/challenger.md +7 -1
- package/plugins/fh-meta/agents/expert.md +1 -1
- package/plugins/fh-meta/agents/fact-checker.md +7 -1
- package/plugins/fh-meta/agents/hub-persona-auditor.md +2 -1
- package/plugins/fh-meta/agents/main-player.md +4 -1
- package/plugins/fh-meta/agents/persona-innovator.md +10 -2
- package/plugins/fh-meta/skills/agent-composer/SKILL.md +2 -2
- package/plugins/fh-meta/skills/apex-review/SKILL.md +5 -0
- package/plugins/fh-meta/skills/asset-placement-gate/SKILL.md +38 -8
- package/plugins/fh-meta/skills/auto-decorrelation/SKILL.md +16 -2
- package/plugins/fh-meta/skills/context-doctor/SKILL_detail.md +45 -10
- package/plugins/fh-meta/skills/corpus-grounding-expander/SKILL.md +14 -5
- package/plugins/fh-meta/skills/cross-ecosystem-synergy-detection/SKILL.md +93 -30
- package/plugins/fh-meta/skills/deep-clarify/SKILL.md +28 -9
- package/plugins/fh-meta/skills/fh/SKILL.md +4 -0
- package/plugins/fh-meta/skills/frontier-digest/SKILL.md +64 -8
- package/plugins/fh-meta/skills/frontier-digest/SKILL_detail.md +20 -7
- package/plugins/fh-meta/skills/goal-quench/SKILL.md +48 -15
- package/plugins/fh-meta/skills/goal-quench/SKILL_detail.md +58 -11
- package/plugins/fh-meta/skills/harness-doctor/SKILL_detail.md +109 -33
- package/plugins/fh-meta/skills/harvest-loop/SKILL.md +6 -1
- package/plugins/fh-meta/skills/hub-cc-pr-reviewer/SKILL.md +126 -17
- package/plugins/fh-meta/skills/install-doctor/SKILL.md +50 -14
- package/plugins/fh-meta/skills/install-wizard/SKILL.md +26 -7
- package/plugins/fh-meta/skills/install-wizard/SKILL_detail.md +68 -21
- package/plugins/fh-meta/skills/memory-hygiene/SKILL.md +64 -17
- package/plugins/fh-meta/skills/meta-prompt-builder/SKILL.md +38 -4
- package/plugins/fh-meta/skills/persona-roster-expander/SKILL.md +15 -7
- package/plugins/fh-meta/skills/plugin-recommender/SKILL.md +39 -11
- package/plugins/fh-meta/skills/plugin-recommender/SKILL_detail.md +24 -7
- package/plugins/fh-meta/skills/prompt-regression/SKILL.md +54 -11
- package/plugins/fh-meta/skills/salience-splitter/SKILL.md +120 -7
- package/plugins/fh-meta/skills/salience-splitter/SKILL_detail.md +46 -13
- package/plugins/fh-meta/skills/sim-conductor/SKILL_detail.md +28 -3
- package/plugins/fh-meta/skills/steel-quench/SKILL.md +3 -1
- package/plugins/fh-meta/skills/verify-bidirectional/SKILL.md +72 -14
- package/scripts/compaction_probe.sh +153 -10
- package/scripts/consent_registry_check.sh +63 -0
- package/scripts/count_check.sh +47 -1
- package/scripts/degrade_direction_scan.sh +276 -6
- package/scripts/degrade_probe_capability.sh +105 -0
- package/scripts/lane_runner_check.sh +425 -0
- package/scripts/package_coverage_check.sh +190 -35
- package/scripts/psa_probe_capability.sh +78 -0
- package/scripts/psa_scan_lib.sh +164 -0
- package/scripts/public_surface_scan_files.sh +38 -0
- package/scripts/selfcheck.sh +346 -28
- package/scripts/test_capability_entrypoint_shipping.sh +132 -0
- package/scripts/test_consent_registry.sh +54 -0
- package/scripts/test_count_check_readme_format_lanes.sh +75 -0
- package/scripts/test_degrade_scan_shell_probes.sh +415 -0
- package/scripts/test_marker_crossfamily_lanes.sh +10 -1
- package/scripts/test_marker_floor_lanes.sh +25 -1
- package/scripts/test_psa_singlefile_lanes.sh +288 -0
- package/scripts/test_reviewer_capability_conformance.sh +10 -1
- package/scripts/test_selfcheck_state_lanes.sh +173 -0
- package/scripts/validate_yaml.sh +146 -0
- package/templates/degrade_direction_scan.sh +276 -6
- package/templates/goal-quench-settings-merged.json +30 -0
|
@@ -157,7 +157,17 @@ done
|
|
|
157
157
|
#### 5-2. CATALOG.md Open Item Count
|
|
158
158
|
|
|
159
159
|
```bash
|
|
160
|
-
|
|
160
|
+
# An ABSENT CATALOG.md must not render as "0 open items" — that is the not-found-as-zero class this
|
|
161
|
+
# whole file exists to close, and the old form produced it twice over: `2>/dev/null` swallowed awk's
|
|
162
|
+
# error, and `grep -c … || echo "0"` printed a SECOND "0" on no-match (the counter already prints
|
|
163
|
+
# its own "0" before exiting non-zero). `|| true` is the safe fallback — it prints nothing.
|
|
164
|
+
if [ ! -f CATALOG.md ]; then
|
|
165
|
+
echo "5-2 UNMEASURED: CATALOG.md not found — absent is not 'no open items'"
|
|
166
|
+
else
|
|
167
|
+
open_count=$(awk '/^### /{count++} count<=5{print}' CATALOG.md | grep -c "^- Open:" || true)
|
|
168
|
+
open_count=$(( ${open_count:-0} + 0 ))
|
|
169
|
+
echo "5-2 Open items (5 most recent sections): ${open_count}"
|
|
170
|
+
fi
|
|
161
171
|
```
|
|
162
172
|
|
|
163
173
|
> Do not use `grep -c "^- Open:" CATALOG.md` — returns hundreds as false positives counting entire history.
|
|
@@ -165,12 +175,24 @@ awk '/^### /{count++} count<=5{print}' CATALOG.md 2>/dev/null | grep -c "^- Open
|
|
|
165
175
|
#### 5-3. Field Project CLAUDE.md Existence
|
|
166
176
|
|
|
167
177
|
```bash
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
178
|
+
# The index file may not exist at all. `not found` != `0 problems` — an absent
|
|
179
|
+
# index must print MISSING INDEX, never an empty (= "all OK") result.
|
|
180
|
+
field_index=.claude/memory/reference_field_projects.md
|
|
181
|
+
if [ ! -f "$field_index" ]; then
|
|
182
|
+
echo "MISSING INDEX: $field_index (5-3 UNMEASURED — not a pass)"
|
|
183
|
+
else
|
|
184
|
+
grep -oE '`~/[^`]+`' "$field_index" \
|
|
185
|
+
| tr -d '`' | sed "s|~|$HOME|g" | while read p; do
|
|
186
|
+
[ -f "$p/CLAUDE.md" ] && echo "OK: $p" || echo "MISSING CLAUDE.md: $p"
|
|
187
|
+
done
|
|
188
|
+
fi
|
|
172
189
|
```
|
|
173
190
|
|
|
191
|
+
> Known-pair calibration for this block: a **known-positive** path that does exist
|
|
192
|
+
> (`.claude/rules/fh_4axis_gate.md`) must print its `OK:`/`MISSING CLAUDE.md:` verdict, while an
|
|
193
|
+
> absent index must print `MISSING INDEX`. Do not add `2>/dev/null` back — it was what turned a
|
|
194
|
+
> non-existent directory into a silent zero-byte "everything is fine".
|
|
195
|
+
|
|
174
196
|
---
|
|
175
197
|
|
|
176
198
|
## §L5-Detail — Bash Scripts for L5-A, L5-B, L5-C
|
|
@@ -178,23 +200,33 @@ grep -oE '`~/[^`]+`' .claude/memory/reference_field_projects.md 2>/dev/null \
|
|
|
178
200
|
### L5-A Skill Activity (bash)
|
|
179
201
|
|
|
180
202
|
```bash
|
|
203
|
+
# SHELL PORTABILITY (2026-08-12, measured): the earlier form used `for f in $recent_sessions`.
|
|
204
|
+
# bash word-splits an unquoted parameter expansion on IFS; **zsh does not** (SH_WORD_SPLIT is off by
|
|
205
|
+
# default, and zsh is the macOS login shell these fences get pasted into). Under zsh the loop ran
|
|
206
|
+
# ONCE with the entire newline-joined list as a single filename, every grep missed, and this block
|
|
207
|
+
# reported EVERY skill as INACTIVE_90D — the harness declaring its own skills dead. Note the
|
|
208
|
+
# direction: not a permissive false clean, a false ALARM, which is why no lane caught it.
|
|
209
|
+
# `printf | while IFS= read -r` is the portable iteration; it is also correct for names with spaces.
|
|
210
|
+
# `grep -qi` (not `-li`) — `-l` printed each matching filename into the report as noise.
|
|
211
|
+
# `count=$(... | grep -c x || true)`: `|| true` PRINTS NOTHING, so it cannot produce the "0\n0"
|
|
212
|
+
# two-line disarm that `|| echo 0` produces (see the L5-C note below). Do not "simplify" it back.
|
|
181
213
|
recent_sessions=$(find tracks/ -name "session_*.md" -mtime -30 2>/dev/null)
|
|
182
214
|
if [ -z "$recent_sessions" ]; then
|
|
183
215
|
echo "L5-A SKIP: no session records — re-diagnose after 30 days"
|
|
184
216
|
else
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
217
|
+
sessions_90d=$(find tracks/ -name "session_*.md" -mtime -90 2>/dev/null)
|
|
218
|
+
|
|
219
|
+
ls plugins/fh-meta/skills/ 2>/dev/null | while IFS= read -r skill; do
|
|
220
|
+
[ -n "$skill" ] || continue
|
|
221
|
+
count=$(printf '%s\n' "$recent_sessions" | while IFS= read -r f; do
|
|
222
|
+
[ -f "$f" ] && grep -qi "$skill" "$f" 2>/dev/null && printf 'x\n'
|
|
223
|
+
done | grep -c x || true)
|
|
224
|
+
count=$(( ${count:-0} + 0 ))
|
|
192
225
|
if [ "$count" -eq 0 ]; then
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
done
|
|
226
|
+
count_90d=$(printf '%s\n' "$sessions_90d" | while IFS= read -r f; do
|
|
227
|
+
[ -f "$f" ] && grep -qi "$skill" "$f" 2>/dev/null && printf 'x\n'
|
|
228
|
+
done | grep -c x || true)
|
|
229
|
+
count_90d=$(( ${count_90d:-0} + 0 ))
|
|
198
230
|
if [ "$count_90d" -eq 0 ]; then
|
|
199
231
|
echo "INACTIVE_90D: $skill (no call record in 90 days)"
|
|
200
232
|
else
|
|
@@ -216,7 +248,10 @@ recent_sessions=$(find tracks/ -name "session_*.md" -mtime -30 2>/dev/null)
|
|
|
216
248
|
[ -z "$recent_sessions" ] && echo "L5-B SKIP: no session records" && exit 0
|
|
217
249
|
|
|
218
250
|
# hub-persona-auditor misuse: code PR or internal refactoring context
|
|
219
|
-
for f in $recent_sessions
|
|
251
|
+
# `printf | while read`, not `for f in $recent_sessions` — zsh does not word-split a parameter
|
|
252
|
+
# expansion, so the `for` form scanned one bogus blob filename and reported "no misuse" every time.
|
|
253
|
+
printf '%s\n' "$recent_sessions" | while IFS= read -r f; do
|
|
254
|
+
[ -f "$f" ] || continue
|
|
220
255
|
if grep -q "hub-persona-auditor" "$f" 2>/dev/null; then
|
|
221
256
|
context=$(grep -n "hub-persona-auditor" "$f" | head -3)
|
|
222
257
|
echo "$context" | while IFS=: read linenum rest; do
|
|
@@ -229,7 +264,8 @@ for f in $recent_sessions; do
|
|
|
229
264
|
done
|
|
230
265
|
|
|
231
266
|
# sim-conductor misuse: first run without onboarding context
|
|
232
|
-
|
|
267
|
+
printf '%s\n' "$recent_sessions" | while IFS= read -r f; do
|
|
268
|
+
[ -f "$f" ] || continue
|
|
233
269
|
if grep -q "sim-conductor" "$f" 2>/dev/null; then
|
|
234
270
|
context=$(grep -n "sim-conductor" "$f" | head -3)
|
|
235
271
|
echo "$context" | while IFS=: read linenum rest; do
|
|
@@ -242,8 +278,13 @@ for f in $recent_sessions; do
|
|
|
242
278
|
done
|
|
243
279
|
|
|
244
280
|
# harness-doctor self-loop misuse
|
|
245
|
-
|
|
246
|
-
|
|
281
|
+
printf '%s\n' "$recent_sessions" | while IFS= read -r f; do
|
|
282
|
+
[ -f "$f" ] || continue
|
|
283
|
+
# `grep -c` prints 0 AND exits 1 on no-match, so `|| echo 0` appends a SECOND line
|
|
284
|
+
# ("0\n0") and every later [ -eq/-gt ] test dies with "integer expression expected".
|
|
285
|
+
# `|| true` keeps the exit code from killing the assignment without corrupting the value.
|
|
286
|
+
count=$(grep -c "harness-doctor" "$f" || true)
|
|
287
|
+
count=$(( ${count:-0} + 0 ))
|
|
247
288
|
if [ "$count" -gt 2 ]; then
|
|
248
289
|
echo "L5-B MISUSE (suspected): harness-doctor @ $f — self-loop suspected (${count} mentions in same session)"
|
|
249
290
|
fi
|
|
@@ -281,14 +322,21 @@ if [ "$skill_count" -gt 0 ]; then
|
|
|
281
322
|
fi
|
|
282
323
|
|
|
283
324
|
# E3: CATALOG.md Open item consumption rate
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
325
|
+
# NEVER use `grep -c ... || echo N/A` here: grep -c prints "0" and exits 1 on no-match, so the
|
|
326
|
+
# fallback appends a second line ("0\nN/A"), the != "N/A" test passes, and $(( )) then dies with a
|
|
327
|
+
# syntax error — the E3 line vanishes entirely (silent non-measurement, not a skip).
|
|
328
|
+
# Separate the two questions: (a) is history reachable at all, (b) what is the count.
|
|
329
|
+
current_open=$(awk '/^### /{count++} count<=5{print}' CATALOG.md 2>/dev/null | grep -c "^- Open:" || true)
|
|
330
|
+
current_open=$(( ${current_open:-0} + 0 ))
|
|
331
|
+
past_catalog=$(git show "HEAD@{30 days ago}:CATALOG.md" 2>/dev/null || true)
|
|
332
|
+
if [ -z "$past_catalog" ]; then
|
|
333
|
+
echo "E3_SKIP: git history < 30 days or CATALOG.md absent then (UNMEASURED — not zero)"
|
|
334
|
+
else
|
|
335
|
+
past_open=$(printf '%s\n' "$past_catalog" \
|
|
336
|
+
| awk '/^### /{count++} count<=5{print}' | grep -c "^- Open:" || true)
|
|
337
|
+
past_open=$(( ${past_open:-0} + 0 ))
|
|
288
338
|
consumed=$((past_open - current_open))
|
|
289
339
|
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
340
|
fi
|
|
293
341
|
|
|
294
342
|
# E4: harvest signals
|
|
@@ -318,13 +366,28 @@ if [ ! -f "$manifest" ]; then
|
|
|
318
366
|
&& echo "E7_WARN: ${recent_asset_edits} asset edit(s) in 14d but no edit_manifest.yaml" \
|
|
319
367
|
|| echo "E7: no recent asset edits"
|
|
320
368
|
else
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
369
|
+
# `grep -c` on zero matches prints "0" and exits 1 → `|| echo 0` made this "0\n0", the
|
|
370
|
+
# -eq test then errored out (non-zero = false), and control fell through to the `||` branch:
|
|
371
|
+
# E7_OK. The evolution-loop blindness detector was structurally unable to raise its own alarm.
|
|
372
|
+
# `|| true` + arithmetic normalisation is what makes the WARN arm reachable.
|
|
373
|
+
manifest_recent=$(grep -c "$(date +%Y-%m)" "$manifest" || true)
|
|
374
|
+
manifest_recent=$(( ${manifest_recent:-0} + 0 ))
|
|
375
|
+
if [ "$recent_asset_edits" -gt 0 ] && [ "$manifest_recent" -eq 0 ]; then
|
|
376
|
+
echo "E7_WARN: ${recent_asset_edits} asset edit(s) in 14d but no manifest entry this month"
|
|
377
|
+
else
|
|
378
|
+
echo "E7_OK: edit_manifest.yaml present with ${manifest_recent} entr(ies) this month"
|
|
379
|
+
fi
|
|
325
380
|
fi
|
|
326
381
|
```
|
|
327
382
|
|
|
383
|
+
> **Known-pair calibration (mandatory before trusting E7).** Run both arms:
|
|
384
|
+
> **negative arm** — point `manifest` at a file with no current-month entries while asset edits
|
|
385
|
+
> exist → must print `E7_WARN`; **positive arm** — the real
|
|
386
|
+
> `tracks/_meta/edit_manifest.yaml` → must print `E7_OK` with a non-zero entry count.
|
|
387
|
+
> If the negative arm prints `E7_OK`, the detector is dead and its silence means nothing.
|
|
388
|
+
> Note the `if/else` form: the old `[ ... ] && echo A || echo B` chain also falls to `B`
|
|
389
|
+
> whenever the *first* test is false, which is a second route to the same false pass.
|
|
390
|
+
|
|
328
391
|
---
|
|
329
392
|
|
|
330
393
|
## §Step11 — PR Change Consistency Check Bash Scripts
|
|
@@ -332,13 +395,26 @@ fi
|
|
|
332
395
|
### 11-1. Detect Changed Files
|
|
333
396
|
|
|
334
397
|
```bash
|
|
398
|
+
# Two defects lived here and both produced phantom downstream counts:
|
|
399
|
+
# (1) `return 0` is only valid inside a function/sourced script. Run as a plain block it
|
|
400
|
+
# printed "can only `return' from a function" to stderr and CARRIED ON into 11-2A/B/C.
|
|
401
|
+
# (2) `echo "" | wc -l` is 1, not 0 — so "no changes" was announced as "1 total".
|
|
402
|
+
# `exit 0` actually stops the block, and `grep -c .` counts non-empty lines only.
|
|
335
403
|
changed=$(git diff main..HEAD --name-only 2>/dev/null)
|
|
336
404
|
[ -z "$changed" ] && changed=$(git diff --cached --name-only 2>/dev/null)
|
|
337
|
-
[ -z "$changed" ]
|
|
338
|
-
echo "
|
|
405
|
+
if [ -z "$changed" ]; then
|
|
406
|
+
echo "PR_CHECK: no changes detected vs main — skip (Step 11 UNMEASURED, run nothing below)"
|
|
407
|
+
exit 0
|
|
408
|
+
fi
|
|
409
|
+
changed_count=$(printf '%s\n' "$changed" | grep -c . || true)
|
|
410
|
+
echo "=== Changed files ($(( ${changed_count:-0} + 0 )) total) ==="
|
|
339
411
|
echo "$changed"
|
|
340
412
|
```
|
|
341
413
|
|
|
414
|
+
> Steps 11-2A/B/C consume `$changed` and must not run when it is empty. If you inline this
|
|
415
|
+
> into a larger function, swap `exit 0` for `return 0` — but never leave a bare `return` in a
|
|
416
|
+
> block that is executed directly, which is what silently disarmed the guard.
|
|
417
|
+
|
|
342
418
|
### 11-2A. SKILL.md Changes → Count Drift + README + CATALOG
|
|
343
419
|
|
|
344
420
|
```bash
|
|
@@ -123,7 +123,12 @@ Output final proposal list → Y: PR creation / N: persist to tracks/_meta/fh_si
|
|
|
123
123
|
|
|
124
124
|
### Step 3.75 — Critic (Isolated Agent)
|
|
125
125
|
|
|
126
|
-
>
|
|
126
|
+
> Isolation = the Critic does not inherit the synthesizer's reasoning chain. **This is an FH design
|
|
127
|
+
> decision, not a borrowed one.** Its evidence is arXiv 2605.00914 (*The Cost of Consensus*): plurality
|
|
128
|
+
> voting discards correct answers already present in the pool (oracle gap ≤32.3pp) and peer rationales
|
|
129
|
+
> destabilize previously-correct reasoning (≤70.0%) — so the reviewer must not stand inside the
|
|
130
|
+
> generator's chain. *Corrected 2026-08-11: this line previously cited SAGE (arXiv 2603.15255) as the
|
|
131
|
+
> isolation source. SAGE's four agents **co-evolve from a shared backbone** — the opposite structure.*
|
|
127
132
|
|
|
128
133
|
Critic evaluation: Done When logic validation · failure mode exploration (2+ edge cases) · claim vs. implementation alignment · scope appropriateness (Too Narrow / Too Broad).
|
|
129
134
|
|
|
@@ -73,18 +73,48 @@ Self-precision catch areas after first cc review (following previous PR self-cat
|
|
|
73
73
|
- Check explicit statement that audience-specific guides are limited to original developer environment
|
|
74
74
|
- Check explicit statement of organization-specific areas
|
|
75
75
|
|
|
76
|
-
Self-catch areas 0 items = skip this entire catch matrix
|
|
76
|
+
Self-catch areas 0 items = skip this entire catch matrix — do not pad with token-filling to make the section look populated.
|
|
77
77
|
|
|
78
78
|
### Step 4. Review Comment Attachment
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
**Mandatory before any `gh pr comment`: run `/public-surface-audit` over the composed comment text.**
|
|
81
|
+
A PR comment is a **paste on a public surface**, and the repo's mechanical privacy floor does not
|
|
82
|
+
reach it — the pre-commit confidentiality guard scans *staged tracked content* and has **no view of
|
|
83
|
+
PR-body text** (`.claude/rules/fh_4axis_gate.md §Reviewer-visible evidence` says so explicitly).
|
|
84
|
+
This step's own inputs make that acute: Step 2 matrix #2 greps the operator's **local memory files**,
|
|
85
|
+
so an unfiltered paste can carry absolute home paths and private memory prose onto a public PR.
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
verdict CLEAN → attach (automatic, within this skill's authority)
|
|
89
|
+
verdict REVIEW / LEAK → do NOT attach. Redact the flagged spans, re-scan, then attach
|
|
90
|
+
verdict NOT_CONFIGURED, or the
|
|
91
|
+
skill is unavailable → do NOT attach automatically. This is an irreversible surface
|
|
92
|
+
(a posted comment is public the instant it lands and may be
|
|
93
|
+
mirrored before deletion) → **fail-closed**: hand the composed
|
|
94
|
+
text to the operator, or take an explicit logged override
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**Never paste raw Step 2 grep output.** Write a *sanitized capsule* — what was checked, what it
|
|
98
|
+
returned, what was found — never the matched lines themselves. Same rule as the marker: the file is
|
|
99
|
+
a local artifact, the capsule is what crosses the boundary.
|
|
100
|
+
|
|
101
|
+
Then attach the review comment (8-matrix results + self-catch + refinement suggestions + merge
|
|
102
|
+
recommendation) via `gh pr comment`.
|
|
81
103
|
|
|
82
104
|
> **Detail**: See `SKILL_detail.md §Step 4 Comment Template` — `gh pr comment` heredoc template — read when attaching the comment.
|
|
83
105
|
|
|
84
106
|
### Step 5. Admin Override Merge Recommendation
|
|
85
107
|
|
|
86
108
|
**User decision delegation** (this skill = review/recording automation / no merge authority):
|
|
87
|
-
-
|
|
109
|
+
- **Read the branch-protection state at run time — never from this line.** This repo moved to
|
|
110
|
+
`enforce_admins: true` + `required_approving_review_count: 0` on 2026-07-20, and an earlier version
|
|
111
|
+
of this bullet still claimed `false`: a gate skill was recommending an override on a **field that
|
|
112
|
+
had already flipped**. Protection is also two independent layers (legacy + rulesets, strictest
|
|
113
|
+
wins), so one object is never the effective answer — check both:
|
|
114
|
+
`gh api repos/{owner}/{repo}/branches/main/protection` **and**
|
|
115
|
+
`gh api repos/{owner}/{repo}/rules/branches/main`
|
|
116
|
+
- Self-approve is impossible when this cc authored the PR → after a completed review, `--admin` is
|
|
117
|
+
the normal route, not a shortcut
|
|
88
118
|
- Self-approve blocked (GHE policy) → admin override path adherence
|
|
89
119
|
- When this cc authored the change, admin override path is mandatory
|
|
90
120
|
- N+1th operation proof = baseline stabilization acceleration path
|
|
@@ -96,39 +126,118 @@ Attach the review comment (8-matrix results + self-catch + refinement suggestion
|
|
|
96
126
|
| Stage | Approval |
|
|
97
127
|
|---|---|
|
|
98
128
|
| Step 1~3 check auto-activation | **Automatic** (editable afterward) |
|
|
99
|
-
| Step 4 review comment attachment | **Automatic** (
|
|
129
|
+
| Step 4 review comment attachment | **Automatic only after `/public-surface-audit` on the comment text returns CLEAN.** REVIEW/LEAK → redact and re-scan; NOT_CONFIGURED or audit unavailable → **fail-closed**, hand to the operator (a posted comment is public on landing) |
|
|
100
130
|
| Step 5 admin override merge execution | **User decision** (this skill = recommendation only / no merge authority) |
|
|
101
131
|
|
|
102
132
|
## Constraints
|
|
103
133
|
|
|
104
134
|
- **This skill = review/recording automation / no merge authority** — user admin override or other reviewer merge decision
|
|
105
135
|
- **No single-person decision application** — following `fact-checker` rule (narrow 1 / broad N+1 / this cc self-catch joins fact-checker count)
|
|
106
|
-
- **Simplification guard consistency**
|
|
107
|
-
- **Markdown editing discipline mandatory**
|
|
108
|
-
- **Frontmatter description plain text only baseline**
|
|
136
|
+
- **Simplification guard consistency** — when creating/modifying this skill, update SKILL.md only. No new auxiliary files
|
|
137
|
+
- **Markdown editing discipline mandatory** — Edit first. No Write
|
|
138
|
+
- **Frontmatter description plain text only baseline** — avoid markdown bold
|
|
139
|
+
|
|
140
|
+
> The three rules above were previously each attributed to a `memory feedback_*.md` file. Those files
|
|
141
|
+
> do not exist (verified 2026-08-11 against the operator's memory root, with a known-positive control
|
|
142
|
+
> in the same run). The **rules stand on their own**; only the pointers were dead, and citing a
|
|
143
|
+
> non-resolving file as the authority is the phantom-reference class this skill is supposed to catch.
|
|
144
|
+
> Do not re-attach a memory citation here unless `ls` resolves it **in the same run that cites it**.
|
|
109
145
|
|
|
110
146
|
> **Detail**: See `SKILL_detail.md §Sister Asset Utilization Path`, `§External User Environment Adaptation Path`, `§Disable Path`, `§Persona Synergy Catch` — cross-ecosystem utilization, external-environment fallback, own-PRS disable resolution, and deep-insight simultaneous-activation handling — read when operating in an external user environment, resolving own-PRS conflict, or coordinating with deep-insight.
|
|
111
147
|
|
|
112
148
|
## Done When
|
|
113
149
|
|
|
150
|
+
This is a **gate/routing skill** — its output is a merge verdict — so every judged condition below
|
|
151
|
+
names its adversarial pairing. No judge-only path.
|
|
152
|
+
|
|
114
153
|
```
|
|
115
154
|
All 5 Steps completed
|
|
116
|
-
|
|
155
|
+
— mandatory-pass: each step produced its output or is marked N/A with a reason
|
|
156
|
+
|
|
157
|
+
+ Baseline consistency check 8-matrix results output (OK/WARN/BLOCK each item)
|
|
158
|
+
— measured: count items REPORTED vs items ACTUALLY CHECKED; the two must
|
|
159
|
+
match. Matrix #2 (memory baseline) reports SKIPPED when no memory file
|
|
160
|
+
resolves — it is never folded into the pass count (see §References)
|
|
161
|
+
|
|
162
|
+
+ Axis 1 run in --pr mode with a typed verdict read from
|
|
163
|
+
REGRESSION_GUARD_RESULT_FILE
|
|
164
|
+
— mandatory-pass: result is `pass` or `block`. `skip` and exit 3 are NOT
|
|
165
|
+
passes; they mean Axis 1 did not examine this PR and the recommendation
|
|
166
|
+
may not cite it as green
|
|
167
|
+
|
|
168
|
+
+ /public-surface-audit run over the composed comment text BEFORE any
|
|
169
|
+
gh pr comment
|
|
170
|
+
— mandatory-pass, fail-closed: CLEAN attaches; REVIEW/LEAK redact-and-rescan;
|
|
171
|
+
NOT_CONFIGURED or audit unavailable hands to the operator. A posted comment
|
|
172
|
+
is irreversible, so tooling-down is a block, never a free skip
|
|
173
|
+
|
|
117
174
|
+ Review comment attached via gh pr comment command
|
|
118
|
-
|
|
119
|
-
|
|
175
|
+
— mandatory-pass: the comment URL is returned by the command
|
|
176
|
+
|
|
177
|
+
+ Admin override merge recommendation output (merge execution is user's
|
|
178
|
+
decision)
|
|
179
|
+
— judged; adversarial pairing: the branch-protection state is re-read at run
|
|
180
|
+
time from BOTH layers (`.../branches/main/protection` and
|
|
181
|
+
`.../rules/branches/main`, strictest wins) in the same run that recommends.
|
|
182
|
+
A recommendation citing this file's prose instead of a live read is
|
|
183
|
+
unfounded — that exact defect already shipped once here, on a field that
|
|
184
|
+
had flipped
|
|
185
|
+
|
|
186
|
+
+ External verification path: an isolated Critic agent can reach the same
|
|
187
|
+
verdict from the artifacts alone
|
|
188
|
+
— judged; adversarial pairing: the reviewer-visible evidence must be
|
|
189
|
+
reproducible WITHOUT the author's local files. Any verdict resting on a
|
|
190
|
+
gitignored local artifact ships labelled LOCAL-ONLY ATTESTATION -
|
|
191
|
+
UNVERIFIED, which leaves the condition UNMET rather than met
|
|
192
|
+
(`.claude/rules/fh_4axis_gate.md` §Reviewer-visible evidence)
|
|
120
193
|
```
|
|
121
194
|
|
|
122
|
-
**→ Mandatory when PR contains SKILL.md / rules / templates changes:
|
|
195
|
+
**→ Mandatory when PR contains SKILL.md / rules / templates changes: run Axis 1 (backward check) in
|
|
196
|
+
`--pr` mode, against the PR's head branch** — before the merge recommendation is issued. If
|
|
197
|
+
regression_guard reports an M-tier block, the merge recommendation must change to ❌ regardless of
|
|
198
|
+
other checks.
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
# Precondition: the PR head branch must exist locally. This skill reads the PR via `gh pr diff`
|
|
202
|
+
# without checking anything out, so fetch the head ref first or --pr has nothing to resolve.
|
|
203
|
+
PR_BRANCH="$(gh pr view "$PR" --json headRefName -q .headRefName)"
|
|
204
|
+
git fetch origin "$PR_BRANCH":"refs/remotes/origin/$PR_BRANCH" # skip if already present
|
|
205
|
+
bash templates/regression_guard.sh --pr "origin/$PR_BRANCH"
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
⚠️ **Do not run it with no arguments.** Bare `bash templates/regression_guard.sh` diffs the **working
|
|
209
|
+
tree**, and this skill's own workflow leaves the reviewer standing on a clean `main` — so the bare
|
|
210
|
+
form returns `REGRESSION_GUARD_RESULT=skip` with `exit 0` **100% of the time**, and the mandatory
|
|
211
|
+
Axis-1 gate never examines the PR at all. Measured 2026-08-11 on a clean checkout: bare form →
|
|
212
|
+
`rc=0 / result=skip`; `--pr <branch>` on the same commit → `rc=0 / result=pass` having actually read
|
|
213
|
+
the changed SKILL.md. Canonical form is `--pr {BRANCH}` (`.claude/rules/fh_4axis_gate.md`).
|
|
214
|
+
|
|
123
215
|
**Read the verdict from the typed channel, not the exit code** — `exit 0` means pass **or** skip
|
|
124
216
|
(not-checked). Run with `REGRESSION_GUARD_RESULT_FILE=/tmp/rg.$$` and read `result=` from that file:
|
|
125
|
-
`skip` means Axis 1 **did not examine** this PR (no matching file
|
|
126
|
-
as
|
|
127
|
-
|
|
217
|
+
`skip` means Axis 1 **did not examine** this PR (no matching file, or the wrong invocation form) —
|
|
218
|
+
record it as "Axis 1 N/A", never as a green check. `exit 3` means the invocation itself failed
|
|
219
|
+
(unresolvable branch) — also not a pass; fetch the ref and re-run. A merge recommendation that cites
|
|
220
|
+
an unexamined Axis 1 as PASS is the 2026-07-22 fail-open class.
|
|
128
221
|
|
|
129
222
|
## References
|
|
130
223
|
|
|
131
|
-
|
|
132
|
-
|
|
224
|
+
> ⚠️ **The memory filenames below were audited 2026-08-11 and **none of them exist** — 8/8 absent in
|
|
225
|
+
> the operator's own memory root, i.e. they were never reachable, not merely absent externally. They
|
|
226
|
+
> are kept, struck, as the record of a phantom-reference class: a gate skill citing rule bodies that
|
|
227
|
+
> resolve nowhere, while matrix #2 silently "skips" and the run still reports an 8-matrix pass.
|
|
228
|
+
> **Matrix #2 is therefore a 7-matrix in practice** — report it as `matrix 2: SKIPPED (no resolvable
|
|
229
|
+
> memory baseline)` rather than folding it into the pass count (`not found ≠ 0`).
|
|
230
|
+
> Re-populate this list only with paths verified by `ls` **in the same run that cites them**.
|
|
231
|
+
>
|
|
232
|
+
> **Arithmetic reconciled 2026-08-11**: the "8/8" above is now true of the list below — all 8 cited
|
|
233
|
+
> filenames are struck (re-verified in one run: 8 cited / 8 absent, with a known-positive and a
|
|
234
|
+
> known-negative control). Previously only 7 were struck while the 8th
|
|
235
|
+
> (`feedback_autonomous_commit_proposal`) was still cited live, and three more were cited as live
|
|
236
|
+
> authority up in §Constraints and §Step 3 — where an executor actually reads, since References is
|
|
237
|
+
> not on the execution path. **Those live citations are removed; the rules they carried are stated
|
|
238
|
+
> directly.** A struck entry in References is not a fix if the same name is still load-bearing above.
|
|
239
|
+
|
|
240
|
+
- ~~Rule body: `memory feedback_command_tower_gate.md` + `memory feedback_field_to_hub_sync_protocol.md`~~ — **absent (verified 2026-08-11)**
|
|
241
|
+
- ~~Consistency rules: `feedback_simplification_evidence` · `feedback_markdown_edit_discipline` · `feedback_skill_frontmatter_description_plain_text` · `feedback_bidirectional_self_validation` · `feedback_reference_own_hub_assets_first`~~ — **absent (verified 2026-08-11)**
|
|
133
242
|
- Sister skills: `cross-ecosystem-synergy-detection` (sister asset cluster baseline) · `verify-bidirectional` (bidirectional self-validation automation / self-catch auxiliary axis) · `harvest-loop` (weekly audit automation / operation proof accumulation cross-link)
|
|
134
|
-
- Autonomous commit proposal §2.19 baseline: `memory feedback_autonomous_commit_proposal.md
|
|
243
|
+
- ~~Autonomous commit proposal §2.19 baseline: `memory feedback_autonomous_commit_proposal.md`~~ — **absent (verified 2026-08-11)**. The rule it stood for is live and lives in `CLAUDE.md §AI Contribution Model`: development-source automation is allowed, PR submission requires explicit human approval. Cite that, not this filename.
|
|
@@ -221,20 +221,38 @@ If existing retrospective/audit files exist → `harvest-loop` will create files
|
|
|
221
221
|
# Check MCP server transport settings
|
|
222
222
|
grep -r "\"transport\"" .mcp.json 2>/dev/null | grep -i "http\|sse"
|
|
223
223
|
|
|
224
|
-
# List MCP servers using HTTP transport
|
|
225
|
-
|
|
226
|
-
|
|
224
|
+
# List MCP servers using HTTP transport.
|
|
225
|
+
# `except: pass` made this exit 0 on ANY failure, so the `|| echo` fallback was dead code and a
|
|
226
|
+
# corrupt .mcp.json rendered identically to "no risky servers" — a silent pass on a security check.
|
|
227
|
+
# Four states, four distinct exits: absent(0) · unparseable(2) · risky(1) · all-stdio(0).
|
|
228
|
+
python3 - <<'PY'
|
|
229
|
+
import json, os, sys
|
|
230
|
+
p = '.mcp.json'
|
|
231
|
+
if not os.path.exists(p):
|
|
232
|
+
print(' MCP-CHECK: NOT-APPLICABLE — .mcp.json absent (no MCP servers configured)')
|
|
233
|
+
sys.exit(0)
|
|
227
234
|
try:
|
|
228
|
-
d = json.load(open(
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
235
|
+
d = json.load(open(p))
|
|
236
|
+
except Exception as e:
|
|
237
|
+
print(f' MCP-CHECK: UNPARSEABLE — {p}: {e}')
|
|
238
|
+
print(' Transport risk UNMEASURED — this is NOT a pass. Fix the file and re-run.')
|
|
239
|
+
sys.exit(2)
|
|
240
|
+
servers = (d.get('mcpServers') or {})
|
|
241
|
+
risky = [(n, (c or {}).get('transport', 'stdio')) for n, c in servers.items()
|
|
242
|
+
if (c or {}).get('transport', 'stdio') != 'stdio']
|
|
243
|
+
if risky:
|
|
244
|
+
for n, t in risky:
|
|
245
|
+
print(f' WARNING {n}: transport={t} — verify localhost binding + auth')
|
|
246
|
+
sys.exit(1)
|
|
247
|
+
print(f' MCP-CHECK: PASS — {len(servers)} server(s), all stdio')
|
|
248
|
+
PY
|
|
236
249
|
```
|
|
237
250
|
|
|
251
|
+
> **Read the exit code, not just the text.** `2` (unparseable) is an *unmeasured* check and must be
|
|
252
|
+
> reported 🟧 in Step 3, never folded into 🟩. Known-pair calibration for this block: a deliberately
|
|
253
|
+
> truncated `.mcp.json` must yield `2`, and a config with one `transport: http` server must yield `1`.
|
|
254
|
+
> If both print nothing, the check is dead.
|
|
255
|
+
|
|
238
256
|
**Known MCP HTTP transport vulnerability patterns** (based on HTTP port exposure security principles): When MCP servers using HTTP/SSE transport expose ports without authentication, remote access risk within local networks may occur. stdio transport is not affected.
|
|
239
257
|
|
|
240
258
|
| Transport | Risk |
|
|
@@ -283,11 +301,29 @@ If you installed only the plugin in a different project cwd:
|
|
|
283
301
|
## Done When
|
|
284
302
|
|
|
285
303
|
```
|
|
286
|
-
|
|
287
|
-
+ Step
|
|
288
|
-
|
|
304
|
+
Steps 0~4 completed (mandatory-pass)
|
|
305
|
+
+ Step 0 node-floor results recorded per check, each as one of
|
|
306
|
+
PASS / FAIL / UNMEASURED — never blank (measured: 2 floors —
|
|
307
|
+
hook exec-bit, SessionStart
|
|
308
|
+
registration)
|
|
309
|
+
+ Step 2-6 MCP transport check exited 0/1/2 and the exit code is
|
|
310
|
+
carried into the Step 3 tier (2 = UNMEASURED → 🟧, never 🟩) (mandatory-pass)
|
|
311
|
+
+ Step 3 diagnosis report emitted with a tier per area
|
|
312
|
+
(🟥 immediate action / 🟧 check recommended / 🟩 no conflicts) (mandatory-pass)
|
|
313
|
+
+ Verdict is derived from the recorded per-area tiers: 🟩 only if
|
|
314
|
+
every area is 🟩 AND none is UNMEASURED (measured: count of
|
|
315
|
+
non-🟩 areas == 0)
|
|
289
316
|
```
|
|
290
317
|
|
|
318
|
+
**Why `Steps 0~4`, not `1~4`**: Step 0 holds the only *mechanical floor* checks in this skill (hook
|
|
319
|
+
exec-bit, SessionStart registration, Node floor). Leaving it outside the completion condition let a
|
|
320
|
+
run report "done" having never touched the one part that is not judgement.
|
|
321
|
+
|
|
322
|
+
**Why the verdict is counted, not stated**: the previous condition was `"Plugin install is safe in
|
|
323
|
+
current environment" confirmed` — that measures whether a *sentence was printed*, which a run
|
|
324
|
+
satisfies by printing it. An unmeasured area (e.g. an unparseable `.mcp.json`) must not be
|
|
325
|
+
absorbed into 🟩; absence of a finding is not a finding of absence.
|
|
326
|
+
|
|
291
327
|
## Simplification Guard
|
|
292
328
|
|
|
293
329
|
- 0 existing assets (new environment) → output "New environment. No conflicts." and exit immediately in Step 1
|
|
@@ -301,13 +301,32 @@ On Claude API / MCP failure → refer to [`references/fallback-guide.md`](../../
|
|
|
301
301
|
## Done When
|
|
302
302
|
|
|
303
303
|
```
|
|
304
|
-
☐ Environment detection complete: shell, CC version, OS, project type
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
☐
|
|
308
|
-
|
|
309
|
-
☐
|
|
310
|
-
|
|
304
|
+
☐ Environment detection complete: shell, CC version, OS, project type
|
|
305
|
+
identified — each field carries a value or the literal "unknown",
|
|
306
|
+
never blank (measured: 4 fields resolved)
|
|
307
|
+
☐ Settings probe distinguished ABSENT / UNPARSEABLE / OK — an
|
|
308
|
+
unparseable config is never treated as absent (mandatory-pass)
|
|
309
|
+
☐ Gap diagnosis output: present vs missing items listed (measured: count of items
|
|
310
|
+
present + missing == items
|
|
311
|
+
scanned)
|
|
312
|
+
☐ User approval/decline recorded for each suggested item —
|
|
313
|
+
a missing answer is a decline, never an assumed yes (measured: recorded answers
|
|
314
|
+
== suggested items)
|
|
315
|
+
☐ All approved items installed with no failure state; every
|
|
316
|
+
failure surfaced to the user, not silently skipped (mandatory-pass)
|
|
317
|
+
☐ Acceleration baseline: zshrc block either appended with
|
|
318
|
+
SUBSTITUTED values (no literal "{FH_DIR}" in the target file)
|
|
319
|
+
or explicitly declined and the decline recorded (mandatory-pass)
|
|
320
|
+
☐ Step 3-D dispatch consent recorded in the three-part form
|
|
321
|
+
(quoted words · dated lease · scope) or a recorded decline —
|
|
322
|
+
a two-part record is invalid and counts as absent (mandatory-pass)
|
|
323
|
+
☐ Summary output: "N items installed, M items skipped" where
|
|
324
|
+
N + M equals the number of items offered (measured: N + M == offered)
|
|
325
|
+
☐ Nothing was overwritten that the user did not approve (judged — adversarial pairing:
|
|
326
|
+
re-run the wizard on a
|
|
327
|
+
populated .claude/ and diff
|
|
328
|
+
the tree before/after; any
|
|
329
|
+
unapproved delta is a FAIL)
|
|
311
330
|
```
|
|
312
331
|
|
|
313
332
|
`--dry-run` mode Done When: gap diagnosis report written, no installation executed.
|