@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
|
@@ -222,13 +222,23 @@ echo "CC_HUB_DIR=${CC_HUB_DIR:-not set}"
|
|
|
222
222
|
basename "$(pwd)"
|
|
223
223
|
ls .claude/ 2>/dev/null
|
|
224
224
|
|
|
225
|
-
# CC settings (handle both dict and list for plugins)
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
225
|
+
# CC settings (handle both dict and list for plugins).
|
|
226
|
+
# Split existence from parseability FIRST. The old `cat file | python3 … || echo "not found"` read
|
|
227
|
+
# $? from python, so a CORRUPT settings.json printed "settings.json not found" — the wizard would
|
|
228
|
+
# then happily create a fresh one and silently clobber the user's real (broken) config.
|
|
229
|
+
if [ ! -f .claude/settings.json ]; then
|
|
230
|
+
echo "settings.json: ABSENT"
|
|
231
|
+
else
|
|
232
|
+
python3 - <<'PY' || echo "settings.json: UNPARSEABLE (present but unreadable — NOT the same as absent; do NOT overwrite, ask the user)"
|
|
233
|
+
import json, sys
|
|
234
|
+
try:
|
|
235
|
+
d = json.load(open('.claude/settings.json'))
|
|
236
|
+
except Exception as e:
|
|
237
|
+
print(f' parse error: {e}', file=sys.stderr); sys.exit(2)
|
|
238
|
+
p = d.get('plugins', {})
|
|
239
|
+
print('settings.json: OK — plugins:', list(p.keys()) if isinstance(p, dict) else p)
|
|
240
|
+
PY
|
|
241
|
+
fi
|
|
232
242
|
|
|
233
243
|
# MCP plugin connection status
|
|
234
244
|
python3 -c "import json,os; d=json.load(open(os.path.expanduser('~/.claude.json'))); print('MCP:', list(d.get('mcpServers',{}).keys()))" 2>/dev/null || echo "MCP config not found"
|
|
@@ -319,9 +329,18 @@ Reduction targets are only meta operation rules (PR procedures, commit guides, F
|
|
|
319
329
|
**Detection bash:**
|
|
320
330
|
|
|
321
331
|
```bash
|
|
322
|
-
# Detect existing harness scale
|
|
323
|
-
|
|
324
|
-
|
|
332
|
+
# Detect existing harness scale.
|
|
333
|
+
# `| wc -l || echo 0` is a conditional disarm, not a harmless idiom: with `set -o pipefail` active
|
|
334
|
+
# (which the caller's shell may well have) a failing upstream stage makes the pipeline exit non-zero
|
|
335
|
+
# AFTER wc has already printed its count, so the fallback appends a SECOND line, the value becomes
|
|
336
|
+
# "0\n0", and the `-ge 3` test below dies with "integer expression expected" — on stderr only —
|
|
337
|
+
# leaving the guard silent. Measured both directions 2026-08-12: single line without pipefail,
|
|
338
|
+
# two lines with it. Sanitize instead of falling back.
|
|
339
|
+
CLAUDE_MD_LINES=$(wc -l < CLAUDE.md 2>/dev/null || true)
|
|
340
|
+
RULES_COUNT=$(ls .claude/rules/*.md 2>/dev/null | wc -l || true)
|
|
341
|
+
# head -n1 FIRST, then strip: `tr -dc '0-9'` alone would fuse a two-line "12\n0" into "120".
|
|
342
|
+
CLAUDE_MD_LINES=$(printf '%s\n' "$CLAUDE_MD_LINES" | head -n1 | tr -dc '0-9'); CLAUDE_MD_LINES=${CLAUDE_MD_LINES:-0}
|
|
343
|
+
RULES_COUNT=$(printf '%s\n' "$RULES_COUNT" | head -n1 | tr -dc '0-9'); RULES_COUNT=${RULES_COUNT:-0}
|
|
325
344
|
|
|
326
345
|
echo "CLAUDE.md: ${CLAUDE_MD_LINES} lines"
|
|
327
346
|
echo ".claude/rules/: ${RULES_COUNT} files"
|
|
@@ -493,6 +512,15 @@ propose adding rows to `agent-composer/SKILL.md` Step 1 mapping table in this fo
|
|
|
493
512
|
| {skill name} related task | {skill name} (S) | — |
|
|
494
513
|
```
|
|
495
514
|
|
|
515
|
+
> **Verify this block against a temp file, never against `~/.zshrc`.** Set `ZSHRC_TARGET` to a
|
|
516
|
+
> scratch path and run the five arms: FH_DIR unset → rc=1, nothing written · CC_HUB_DIR unset →
|
|
517
|
+
> rc=1, nothing written · `$FH_DIR` without the script → ABORT, nothing written · consent absent →
|
|
518
|
+
> SKIPPED, nothing written · consent Y with both vars → block appended with values **substituted**
|
|
519
|
+
> and `$HOME`/`$FH_DIR` left literal, then `zsh -c 'source <temp>'` exits 0. Re-running must not
|
|
520
|
+
> duplicate the block. **Beware a contaminated control**: if your own shell already exports
|
|
521
|
+
> `FH_DIR`, the "unset" arm is not actually negative — isolate with `env -u FH_DIR`. That mistake
|
|
522
|
+
> made the first pass of this very verification report a false PASS.
|
|
523
|
+
|
|
496
524
|
Output preview before execution:
|
|
497
525
|
```
|
|
498
526
|
▶ agent-composer mapping update
|
|
@@ -507,18 +535,37 @@ Output preview before execution:
|
|
|
507
535
|
|
|
508
536
|
```bash
|
|
509
537
|
# zshrc hook — preview then confirm. The wizard is AI-mediated: SHOW the user the exact block
|
|
510
|
-
# below and ask in-chat "Append this to ~/.zshrc? (Y/N)" BEFORE running the append.
|
|
511
|
-
#
|
|
512
|
-
#
|
|
513
|
-
#
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
538
|
+
# below and ask in-chat "Append this to ~/.zshrc? (Y/N)" BEFORE running the append.
|
|
539
|
+
#
|
|
540
|
+
# TWO defects were fixed here (2026-08-12), both of which corrupt every future shell:
|
|
541
|
+
# (1) The heredoc was QUOTED (<< 'EOF'), so the literal text `{FH_DIR}` was written to ~/.zshrc.
|
|
542
|
+
# The resulting `source "$FH_DIR/templates/fh_audit_check.zsh"` then resolved to
|
|
543
|
+
# `{FH_DIR}/templates/...` and every subsequent shell start failed with
|
|
544
|
+
# `no such file or directory` (rc=127, reproduced in a sandbox against a temp file).
|
|
545
|
+
# Fix: unquoted heredoc so FH_DIR/CC_HUB_DIR expand AT WRITE TIME, with `\$HOME` and
|
|
546
|
+
# `\$FH_DIR` escaped so THOSE stay literal and resolve at shell-start.
|
|
547
|
+
# (2) The consent gate was a COMMENT ("run only after an explicit in-chat Y"). A comment does
|
|
548
|
+
# not gate anything — pasted or scripted, the block appended unconditionally. It is now a
|
|
549
|
+
# real conditional on FH_WIZARD_ZSHRC_CONSENT, default N (fail-closed).
|
|
550
|
+
#
|
|
551
|
+
# Set FH_WIZARD_ZSHRC_CONSENT=Y only after the user answers Y in chat.
|
|
552
|
+
ZSHRC="${ZSHRC_TARGET:-$HOME/.zshrc}"
|
|
553
|
+
: "${FH_DIR:?FH_DIR is unset — refusing to write a broken source line into $ZSHRC}"
|
|
554
|
+
: "${CC_HUB_DIR:?CC_HUB_DIR is unset — refusing to write an incomplete block into $ZSHRC}"
|
|
555
|
+
if [ ! -f "$FH_DIR/templates/fh_audit_check.zsh" ]; then
|
|
556
|
+
echo "ABORT: \$FH_DIR/templates/fh_audit_check.zsh does not exist — would wire a dead source line"
|
|
557
|
+
elif [ "${FH_WIZARD_ZSHRC_CONSENT:-N}" != "Y" ]; then
|
|
558
|
+
echo "zshrc hook: SKIPPED (no explicit Y) — nothing written"
|
|
559
|
+
elif grep -q "fh_audit_check.zsh" "$ZSHRC" 2>/dev/null; then
|
|
560
|
+
echo "zshrc hook: already present — no change"
|
|
561
|
+
else
|
|
562
|
+
cat >> "$ZSHRC" <<EOF
|
|
563
|
+
export FH_DIR="$FH_DIR"
|
|
564
|
+
export CC_HUB_DIR="$CC_HUB_DIR"
|
|
565
|
+
export CC_SENTINELS_DIR="\$HOME/.cc_sentinels"
|
|
566
|
+
source "\$FH_DIR/templates/fh_audit_check.zsh"
|
|
521
567
|
EOF
|
|
568
|
+
echo "zshrc hook: appended"
|
|
522
569
|
fi
|
|
523
570
|
# On N: do NOT append; record the decline and state its consequence in one line —
|
|
524
571
|
# echo "zshrc_hook" >> "$HOME/.cc_sentinels/{project}_wizard_declined"
|
|
@@ -56,15 +56,31 @@ re-verification is possible).
|
|
|
56
56
|
|
|
57
57
|
### Step 1 — Scan memory/*.md
|
|
58
58
|
|
|
59
|
+
Enumerate **every** root with a per-root state — an absent root and an empty root are different
|
|
60
|
+
facts, and the Step-4 snapshot scope is bound to this enumeration:
|
|
61
|
+
|
|
59
62
|
```bash
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
ls
|
|
63
|
+
for ROOT in "$HOME"/.claude/projects/*/memory "$PWD/memory"; do
|
|
64
|
+
if [ -d "$ROOT" ]; then
|
|
65
|
+
n=$(ls "$ROOT"/*.md 2>/dev/null | wc -l | tr -d ' ')
|
|
66
|
+
echo "EXISTS(n=$n) $ROOT"
|
|
67
|
+
else
|
|
68
|
+
echo "ABSENT $ROOT"
|
|
69
|
+
fi
|
|
70
|
+
done
|
|
63
71
|
```
|
|
64
72
|
|
|
73
|
+
**`ABSENT` is never counted as 0 entries.** Swallowing both into `2>/dev/null` makes "this root does
|
|
74
|
+
not exist here" indistinguishable from "this root is empty" — and the snapshot in Constraints below
|
|
75
|
+
must cover every root reported `EXISTS`, so a root mis-rendered as empty silently narrows the
|
|
76
|
+
snapshot scope.
|
|
77
|
+
|
|
65
78
|
For each file, extract:
|
|
66
79
|
- `metadata.type` from frontmatter
|
|
67
|
-
-
|
|
80
|
+
- **Age source, in this order** (measured over the live corpus, n=267): `metadata.modified`
|
|
81
|
+
(ISO8601, present on 77/267) → else the file's filesystem mtime → else **`AGE-UNKNOWN`**.
|
|
82
|
+
There is **no top-level `date:` field in this corpus** (measured 0/267) — do not look for one,
|
|
83
|
+
and never treat `AGE-UNKNOWN` as fresh.
|
|
68
84
|
- Key factual claims (GitHub URLs, status strings, version numbers, dates)
|
|
69
85
|
|
|
70
86
|
### Step 2 — Classify by Staleness
|
|
@@ -89,7 +105,9 @@ For each stale entry, run the appropriate re-verification:
|
|
|
89
105
|
**Reference type** (URLs, DOIs, GitHub):
|
|
90
106
|
- Use `gh api` for GitHub resources
|
|
91
107
|
- Use `WebFetch` for DOIs and arXiv records
|
|
92
|
-
- Mark `verified_at: YYYY-MM-DD`
|
|
108
|
+
- Mark `metadata.verified_at: YYYY-MM-DD` — **nested under `metadata:`**, the layer this corpus
|
|
109
|
+
actually uses (`metadata:` present on 265/267; a top-level `verified_at` measured 0/267 and would
|
|
110
|
+
be invisible to the Step-1 extractor)
|
|
93
111
|
- Flag `⚠ DRIFTED` if content has changed materially
|
|
94
112
|
|
|
95
113
|
**Project type** (status, milestones):
|
|
@@ -121,19 +139,47 @@ Apply updates? [y / N per item]
|
|
|
121
139
|
|
|
122
140
|
### Step 5 — Record Run
|
|
123
141
|
|
|
142
|
+
Use `printf`, never `echo "…\n…"` — `echo` expands `\n` in zsh but writes it **literally** in bash
|
|
143
|
+
(measured: 6 lines vs 1), which silently produces a one-line file with a broken frontmatter.
|
|
144
|
+
|
|
124
145
|
```bash
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
146
|
+
mkdir -p tracks/_meta
|
|
147
|
+
printf '%s\n' \
|
|
148
|
+
'---' \
|
|
149
|
+
"date: $(date +%Y-%m-%d)" \
|
|
150
|
+
"entries_checked: ${ENTRIES_CHECKED}" \
|
|
151
|
+
"demoted_to_archive: ${DEMOTED}" \
|
|
152
|
+
"orphans_indexed: ${ORPHANS}" \
|
|
153
|
+
"merged: ${MERGED}" \
|
|
154
|
+
"drifted: ${DRIFTED}" \
|
|
155
|
+
"hard_deleted: ${HARD_DELETED}" \
|
|
156
|
+
'---' \
|
|
157
|
+
> "tracks/_meta/memory_hygiene_$(date +%Y-%m-%d).md"
|
|
128
158
|
```
|
|
129
159
|
|
|
160
|
+
**Every count is a measured value from Steps 1–4.** A log still containing a literal `N` (or an
|
|
161
|
+
unexpanded `${…}`) is **an invalid log** — treat that run as not-recorded, because the log's
|
|
162
|
+
existence is what arms the 7-day cadence guard, so a placeholder log suppresses the *next* real run.
|
|
163
|
+
|
|
130
164
|
## Constraints
|
|
131
165
|
|
|
132
166
|
- **No auto-deletion**: Archive candidates are proposed, not deleted. Human confirmation required.
|
|
133
167
|
- **Snapshot before archive (Destructive-Op Gate for memory)**: before applying any confirmed
|
|
134
168
|
archive/removal in Step 4, snapshot **every memory root the entry could live in** first — tar **all**
|
|
135
169
|
roots Step 1 enumerated (`~/.claude/projects/*/memory/` AND hub-local `memory/`), not just one:
|
|
136
|
-
|
|
170
|
+
the snapshot **must be gated on its own exit status** — an unwritable or missing `tracks/_meta`
|
|
171
|
+
makes `tar` exit 1 and produce no tarball (measured), and without a gate the irreversible archive
|
|
172
|
+
proceeds anyway:
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
SNAP="tracks/_meta/memory_snapshot_$(date +%Y%m%d-%H%M%S).tgz"
|
|
176
|
+
mkdir -p tracks/_meta || { echo "SNAPSHOT FAILED (mkdir) — abort archive"; exit 1; }
|
|
177
|
+
tar czf "$SNAP" <each Step-1 root reported EXISTS> || { echo "SNAPSHOT FAILED (tar) — abort archive"; exit 1; }
|
|
178
|
+
[ -s "$SNAP" ] || { echo "SNAPSHOT FAILED (empty tarball) — abort archive"; exit 1; }
|
|
179
|
+
echo "SNAPSHOT OK: $SNAP"
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Only on `SNAPSHOT OK` may the archive proceed — so
|
|
137
183
|
a wrong archive in any scanned root is one-command recoverable (a single-root snapshot can pass while
|
|
138
184
|
the archived entry lived in the other root — bind the scope to the entry, not to "a tarball exists").
|
|
139
185
|
Archive moves entries to a `.archive/` sibling, never hard-deletes (mirrors the Curator's
|
|
@@ -147,14 +193,15 @@ echo "---\ndate: $(date +%Y-%m-%d)\nentries_checked: N\nupdated: N\ndrifted: N\n
|
|
|
147
193
|
|
|
148
194
|
## Done When
|
|
149
195
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
196
|
+
| Condition | Check class |
|
|
197
|
+
|---|---|
|
|
198
|
+
| Step 1~5 complete, every memory root reported `EXISTS(n=…)` or `ABSENT` | **mandatory-pass** |
|
|
199
|
+
| Staleness roster output (Step 2 = mechanical no-LLM pre-pass), with `AGE-UNKNOWN` entries listed separately and not as FRESH | **measured** (age from `metadata.modified` / mtime, not recall) |
|
|
200
|
+
| Re-verification run for all STALE entries | **mandatory-pass** |
|
|
201
|
+
| Each re-verified entry's verdict (VERIFIED / DRIFTED) is correct | **judged** — adversarial pairing: `fh-meta:fact-checker` re-greps the hub for the same claim; any disagreement downgrades the entry to DRIFTED (no judge-only PASS) |
|
|
202
|
+
| User gate presented and responded to (y/N per item) | **mandatory-pass** |
|
|
203
|
+
| If any archive confirmed: snapshot written **and its exit status checked** before the move (`tracks/_meta/memory_snapshot_*.tgz`, spanning every root reported `EXISTS`) | **mandatory-pass** — snapshot must cover the archived entry's dir; `SNAPSHOT OK` printed, not merely "a tarball exists" |
|
|
204
|
+
| Hygiene log written to `tracks/_meta/memory_hygiene_{date}.md` with real counts (no literal `N`, no unexpanded `${…}`) | **measured** |
|
|
158
205
|
|
|
159
206
|
## References
|
|
160
207
|
|
|
@@ -153,11 +153,45 @@ Acceptable form examples:
|
|
|
153
153
|
|
|
154
154
|
## Done When
|
|
155
155
|
|
|
156
|
+
This skill's own Done When must satisfy the 3-part completeness check it imposes on others
|
|
157
|
+
(**measurement subject · measurement timing · version/baseline**). The previous version —
|
|
158
|
+
`All steps 0–3 completed` — met 0 of 3 and matched its own `Unconditioned completion` WARN pattern.
|
|
159
|
+
|
|
156
160
|
```
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
+
Measurement subject: this skill's own output — the prompt draft set
|
|
162
|
+
produced in this invocation (not the dispatched
|
|
163
|
+
agents' results, which this skill never sees)
|
|
164
|
+
Measurement timing: absolute, at end of this run — no comparison to a
|
|
165
|
+
previous run is implied or required
|
|
166
|
+
Version / baseline: the Step 3 checklist and the WARN-trigger table in
|
|
167
|
+
THIS file; note the SKILL.md revision used if the
|
|
168
|
+
table has changed since the draft was written
|
|
169
|
+
|
|
170
|
+
☐ Steps 0–3 each produced their named artifact — a step with no
|
|
171
|
+
artifact is incomplete, not "completed" (measured: 4 steps, 4 artifacts)
|
|
172
|
+
☐ One prompt draft exists per agent named in the dispatch plan (measured: drafts == agents
|
|
173
|
+
in plan)
|
|
174
|
+
☐ Every draft carries all four fields (Goal / Context /
|
|
175
|
+
Constraints / Done When), none empty (measured: 4 fields × N drafts,
|
|
176
|
+
0 empty)
|
|
177
|
+
☐ Each draft's own Done When was run through the 3-part
|
|
178
|
+
completeness check and the WARN-trigger table, with the
|
|
179
|
+
result recorded per draft (mandatory-pass)
|
|
180
|
+
☐ Every Goal was checked against the target agent's declared
|
|
181
|
+
allowed-tools by READING that agent's SKILL.md — not from
|
|
182
|
+
recall (mandatory-pass)
|
|
183
|
+
☐ [WARN] items are surfaced to the user with the reason, and
|
|
184
|
+
the decision is the user's (mandatory-pass)
|
|
185
|
+
☐ Drafts are handed over for review, not dispatched (mandatory-pass)
|
|
186
|
+
☐ The drafts are usable by the target agent as written (judged — adversarial pairing:
|
|
187
|
+
generator and validator are the
|
|
188
|
+
same model, so self-validation
|
|
189
|
+
repeats its own bias. Have the
|
|
190
|
+
target agent, or a different
|
|
191
|
+
model, read one draft cold and
|
|
192
|
+
state what it would do; a
|
|
193
|
+
divergence from the intended
|
|
194
|
+
task is a FAIL)
|
|
161
195
|
```
|
|
162
196
|
|
|
163
197
|
## Simplification Guard
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: persona-roster-expander
|
|
3
3
|
description: Expands a named persona seed into a tiered, judgment-mapped cast — tiering each persona by a domain safety rule, mapping each to a decision-lens in the user's vocabulary, then proposing additional voices with sourced anchors.
|
|
4
4
|
user-invocable: true
|
|
5
|
-
allowed-tools: ["Read", "Grep", "WebSearch", "WebFetch"]
|
|
5
|
+
allowed-tools: ["Read", "Grep", "WebSearch", "WebFetch", "Write", "Agent"]
|
|
6
6
|
model: sonnet
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -15,7 +15,12 @@ caller-supplied safety rule so the expansion stays faithful to the domain's cons
|
|
|
15
15
|
|
|
16
16
|
> Origin: harvested from the-bible (2026-06-20) — an operator persona seed (priest/nun/angel/devil/
|
|
17
17
|
> God/Jesus/Holy-Spirit/apostles) tiered relay-vs-lens by a relay-safety rule and mapped to
|
|
18
|
-
> engineering-judgment lenses, +4 sourced proposals.
|
|
18
|
+
> engineering-judgment lenses, +4 sourced proposals. **The grounds, inline, because the harvest
|
|
19
|
+
> record does not ship**: an ungated persona cast drifts into inventing its own authority — a voice
|
|
20
|
+
> given a lens will speak past what the domain lets it assert — so tiering by a *caller-supplied*
|
|
21
|
+
> rule is what keeps the expansion faithful, and the lens mapping is what makes a named voice
|
|
22
|
+
> usable as a decision instrument instead of flavor. Full harvest record — **hub-local, not
|
|
23
|
+
> distributed in the npm package**:
|
|
19
24
|
> `tracks/_contrib/field_harvest_2026-06-20_gate-locality-and-grounding-capabilities.md`.
|
|
20
25
|
|
|
21
26
|
## Triggers
|
|
@@ -41,14 +46,17 @@ caller-supplied safety rule so the expansion stays faithful to the domain's cons
|
|
|
41
46
|
4. **Propose 2–4 additions** filling lenses the seed doesn't cover (delegate net-new *name*
|
|
42
47
|
generation to the `persona-innovator` agent — this skill's distinct value is the tiering +
|
|
43
48
|
lens-mapping, not naming). For the strongest 2–3, find a real anchor (a sourced
|
|
44
|
-
example/reference)
|
|
45
|
-
|
|
46
|
-
|
|
49
|
+
example/reference); **any remaining proposal ships with a literal `stub:` prefix** — unanchored
|
|
50
|
+
and unlabeled is not an allowed output (see Done When).
|
|
51
|
+
5. **Emit the tiered, lens-mapped cast** (named + proposed) by **writing it to a structured file**
|
|
52
|
+
the system can load (e.g. `personas.json`), then confirm the written file parses. Leaving the
|
|
53
|
+
cast in the response text only does not complete this step.
|
|
47
54
|
|
|
48
55
|
## Done When
|
|
49
56
|
- **Every persona has a tier + lens label + invoke-condition.** *Check class: mandatory-pass (binary — all three fields present per persona).*
|
|
50
|
-
- **
|
|
51
|
-
- **The
|
|
57
|
+
- **Every proposal is either anchored or explicitly labeled a stub.** An anchored proposal names a source/reference that resolves; a proposal without one is emitted with a literal `stub:` prefix and is **not counted as a candidate**. *Check class: mandatory-pass (binary — each proposal carries either a resolving anchor or a `stub:` label; an unanchored, unlabeled proposal is FAIL). Anchor resolution is checked mechanically (fetch/look up the cited reference), not by judgment.* (This is the Done-When floor; Step 4's "strongest 2–3" is the effort target that sits above it — a 4th proposal may ship as `stub:` without violating either.)
|
|
58
|
+
- **The cast is materialized as a loadable artifact** (e.g. `personas.json`) that a consumer can parse — the file exists on disk and a parse of it succeeds against the declared schema (per persona: tier / lens / invoke-condition; per proposal additionally `anchor` or `stub:`). *Check class: mandatory-pass (binary — file exists and parses; a cast that exists only in the response text is UNMET).*
|
|
59
|
+
- **The tiering respects the caller's safety rule** (no persona exceeds its tier's allowed emission). *Check class: judged, pair: dispatch `fh-meta:challenger` at the tier-escalation angle — "find a persona whose lens mapping lets it emit beyond its tier". The pairing is a **different-agent** read; the author's own re-read does not satisfy it. If that agent is unreachable, record `pair: unavailable (<reason>)` — the condition stays UNMET and is **reported as a named residual**, never self-scored closed. It does **not** block delivery: a roster is a reversible artifact, so the degrade direction here is declare-and-ship, not fail-closed (that direction is reserved for irreversible surfaces — publish, delete, history-rewrite). Shipping with an UNMET pairing is honest; silently marking it met is the defect.*
|
|
52
60
|
|
|
53
61
|
## Guards
|
|
54
62
|
- **Caller-supplied safety rule is mandatory** — the skill tiers by the domain's rule, it does not
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: plugin-recommender
|
|
3
3
|
description: Given a task description, searches internal and external open-source ecosystems (including Codex marketplace and Claude Code marketplace) to find and recommend suitable plugins with installation guidance. Recommendation is quality-validation based (marketplace-listed + performance-validated), not source-origin based. Activates on "recommend a plugin", "what tool should I use?", "is there a plugin for this?", "recommend a tool". Also checks for duplicate installations.
|
|
4
4
|
user-invocable: true
|
|
5
|
-
allowed-tools: ["
|
|
5
|
+
allowed-tools: ["Read", "Grep", "Bash", "WebSearch", "WebFetch"]
|
|
6
6
|
model: sonnet
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -59,7 +59,9 @@ Tier is **independent of platform origin** (Anthropic / OpenAI / community). A w
|
|
|
59
59
|
|
|
60
60
|
2. **[Priority 1.5] Internal GHE Sister Assets (partially completed work — Tier 2)**: Check if user's task domain already exists in internal sister asset clusters. Prioritize direct use or adoption of sister assets if the user's task falls within these cluster domains.
|
|
61
61
|
|
|
62
|
-
3. **[Priority 2
|
|
62
|
+
3. **[Priority 2] Organization's Internal GHE (Tier 1–4)**: Search internal GHE with keywords like `claude-plugin`, `gemini-plugin` + user keywords / API search. Replace with your organization's internal GHE orgs.
|
|
63
|
+
|
|
64
|
+
4. **[Priority 2.5] Project Reference/Contribution Path**:
|
|
63
65
|
|
|
64
66
|
For cases where referencing or contributing to the project itself is more appropriate than installing a plugin. Provide guidance when there's intent for medium-term contribution rather than immediate use.
|
|
65
67
|
|
|
@@ -71,9 +73,7 @@ Tier is **independent of platform origin** (Anthropic / OpenAI / community). A w
|
|
|
71
73
|
- `plugin-recommender` [Priority 2.5]: When no immediately usable plugin is available → guide to project-level reference/contribution path (alternative to installing)
|
|
72
74
|
- `cross-ecosystem-synergy-detection`: Discover hidden synergies among already-installed skills (post-install utilization optimization)
|
|
73
75
|
|
|
74
|
-
Activation condition: Automatically entered when Step 2 [Priority 1]~[Priority 2] search yields no suitable plugin.
|
|
75
|
-
|
|
76
|
-
4. **[Priority 2] Organization's Internal GHE (Tier 1–4)**: Search internal GHE with keywords like `claude-plugin`, `gemini-plugin` + user keywords / API search. Replace with your organization's internal GHE orgs.
|
|
76
|
+
Activation condition: Automatically entered when Step 2 [Priority 1]~[Priority 2] search yields no suitable plugin. **This block therefore runs only after [Priority 2] has actually been executed** — the list above is in execution order (1 → 1.5 → 2 → 2.5 → 3), and the priority labels are names, not the run sequence.
|
|
77
77
|
|
|
78
78
|
5. **[Priority 3] External Open-Source Ecosystem**: WebSearch / WebFetch — "best github actions for X", "claude plugin for Y", etc. Simplification guard: defer external install if internal assets suffice.
|
|
79
79
|
|
|
@@ -91,16 +91,18 @@ When queried for a specific capability (e.g., "adversarial reviewer for bash cod
|
|
|
91
91
|
0. **Platform built-ins (Tier 0)** — does a built-in skill/command already cover the capability? Check the live session's available-skills list before any plugin search. A built-in that covers ~80% beats installing a plugin for the rest
|
|
92
92
|
1. **Installed locally** — `.claude/agents/`, `plugins/` in current cwd
|
|
93
93
|
2. **FH native skills** — always-loaded knowledge in `plugins/fh-meta/` and `plugins/fh-commons/`
|
|
94
|
-
3. **Claude Code marketplace** — `claude
|
|
95
|
-
4. **Codex marketplace** — `npx @openai/codex list
|
|
94
|
+
3. **Claude Code marketplace** — `claude plugin list --available --json` (marketplace plugins; `--available` **requires** `--json`) + `claude plugin marketplace list` to see which marketplaces are even configured. There is **no** CLI keyword-search subcommand — filter the JSON yourself, and fall back to the known CC registry (see verified targets above) for anything not in a configured marketplace
|
|
95
|
+
4. **Codex marketplace** — `npx --yes @openai/codex plugin list --available --json` (optionally `-m <marketplace>`) + `npx --yes @openai/codex plugin marketplace list`. Same limitation: no keyword search, filter the JSON
|
|
96
96
|
5. **npm ecosystem** — `@chrono-meta/`, `@anthropic/`, and other known-quality scoped packages
|
|
97
97
|
|
|
98
|
+
⚠️ **A failed or empty discovery lane is NOT "no candidates".** Both CLIs above list only *configured* marketplaces, and a non-zero exit / empty array means the lane did not answer — not that nothing exists. Report each lane's state explicitly (`EXECUTED` / `EMPTY` / `FAILED: <stderr>`) and never render a `FAILED` lane as a zero result; a lane that could not run must be re-run or replaced by the web-search fallback (Priority 3) before you tell the user nothing was found.
|
|
99
|
+
|
|
98
100
|
**Discovery priority**: built-in (Tier 0) > installed > FH native > Tier 1 (any platform) > Tier 2 > Tier 3 > Tier 4
|
|
99
101
|
**Tier 0 guard**: FH native wins over a built-in only when the FH skill adds governance the built-in lacks (e.g. `/goal` → `goal-quench` adds budget+quality gates; code diff review stays with built-in `/code-review`, FH-asset coherence with `hub-cc-pr-reviewer`)
|
|
100
102
|
|
|
101
103
|
**When sim-conductor chains here for persona discovery**: apply the same platform-aware search scoped to persona/simulation/review capability tags. Return discovered agents with their Tier rating so sim-conductor can decide whether to install or use a built-in brief.
|
|
102
104
|
|
|
103
|
-
For discovery bash commands (`claude
|
|
105
|
+
For discovery bash commands (`claude plugin list --available --json`, `npx --yes @openai/codex plugin list --available --json`, npm scoped search), see `SKILL_detail.md §Discovery-Bash`.
|
|
104
106
|
|
|
105
107
|
### Step 2.6: Quality Validation Signals
|
|
106
108
|
|
|
@@ -149,7 +151,8 @@ When user selects desired plugin from recommendation list, help with installatio
|
|
|
149
151
|
## Constraints
|
|
150
152
|
|
|
151
153
|
- **Recommendations, not guarantees**: Does not guarantee plugin performance, stability, or security.
|
|
152
|
-
- **Inbound supply-chain risk
|
|
154
|
+
- **Inbound supply-chain risk — EVERY tier, not just 3/4**: public skill registries have shipped malicious skills at scale (pointers: [HN 47370624](https://news.ycombinator.com/item?id=47370624) — 824 malicious skills reported on ClawHub; [HN 48678603](https://news.ycombinator.com/item?id=48678603) — Snyk ToxicSkills study. Secondary sources — verify before quoting figures). ⚠️ **The channel in both incidents was the marketplace listing itself — i.e. Tier 1/2.** An earlier version of this bullet scoped the warning to Tier 3/4, which inverted its own evidence: it warned loudest exactly where vetting exists and stayed silent where the cited attacks landed. Flag the risk before recommending **any** candidate; a high Tier means *listed and maintained*, never *audited for intent*.
|
|
155
|
+
- **Install string must be resolved, not relayed**: the `<name>` in an install command frequently comes from a web-search result. Before surfacing it, confirm the name resolves to the intended repository (owner/repo matches the source you are citing) — a plausible near-name is the cheapest form of this attack, and installation is irreversible on the machine that runs it.
|
|
153
156
|
- **User consent required**: Does not auto-install without explicit consent.
|
|
154
157
|
- **Search scope limitations**: Only searches within configured search space.
|
|
155
158
|
|
|
@@ -213,9 +216,34 @@ sim-conductor needs persona X (no installed/built-in match)
|
|
|
213
216
|
|
|
214
217
|
```
|
|
215
218
|
All Steps 0~5 completed
|
|
216
|
-
|
|
217
|
-
|
|
219
|
+
— mandatory-pass: each step produced its stated output, or is
|
|
220
|
+
explicitly marked N/A with the reason
|
|
221
|
+
|
|
222
|
+
+ Recommendation list table output (top 2~3 items, Tier + Platform + synergy
|
|
223
|
+
grade included)
|
|
224
|
+
— mandatory-pass: the table exists with all three columns populated
|
|
225
|
+
|
|
226
|
+
+ Every discovery lane reported with an explicit state
|
|
227
|
+
(EXECUTED / EMPTY / FAILED: <stderr>)
|
|
228
|
+
— measured: count lanes attempted vs lanes reporting a state; the two
|
|
229
|
+
numbers must match. A FAILED lane rendered as "no candidates" is a FAIL
|
|
230
|
+
of this condition, not a pass — the CLI lanes have no keyword search and
|
|
231
|
+
see only configured marketplaces, so an empty result is routinely a
|
|
232
|
+
non-answer rather than an absence (`not found` != `0`)
|
|
233
|
+
|
|
234
|
+
+ Install completed after user selection (or install skipped / 5-B migration
|
|
235
|
+
path guided)
|
|
236
|
+
— mandatory-pass: explicit user consent recorded before any install ran
|
|
237
|
+
|
|
218
238
|
+ Duplicate detection results reported
|
|
239
|
+
— mandatory-pass: `claude plugin list` output consulted in this run
|
|
240
|
+
|
|
241
|
+
+ Every install string surfaced to the user resolves to the repository it is
|
|
242
|
+
cited from (§Constraints — resolved, not relayed)
|
|
243
|
+
— judged; adversarial pairing: in the same run, resolve one candidate name
|
|
244
|
+
you already know is correct AND check one near-name variant. If the
|
|
245
|
+
procedure cannot separate that pair, the resolution check is
|
|
246
|
+
UNCALIBRATED and no install string may be presented as verified
|
|
219
247
|
```
|
|
220
248
|
|
|
221
249
|
## Failure Response
|
|
@@ -57,16 +57,24 @@ gh auth status # default host (github.com) only
|
|
|
57
57
|
# Unauthenticated → guide github.com PAT generation above
|
|
58
58
|
```
|
|
59
59
|
|
|
60
|
-
**Claude Code marketplace search
|
|
60
|
+
**Claude Code marketplace discovery** (there is **no** `search` subcommand — `claude mcp search` does not
|
|
61
|
+
exist and exits 1 with `unknown command 'search'`; list, then filter yourself):
|
|
61
62
|
```bash
|
|
62
|
-
claude
|
|
63
|
+
claude plugin marketplace list --json # which marketplaces are configured at all
|
|
64
|
+
claude plugin list --available --json # installed + available marketplace plugins (--available REQUIRES --json)
|
|
63
65
|
```
|
|
64
66
|
|
|
65
|
-
**Codex marketplace
|
|
67
|
+
**Codex marketplace discovery** (`list-agents` does not exist either — the real noun is `plugin`):
|
|
66
68
|
```bash
|
|
67
|
-
npx @openai/codex list
|
|
69
|
+
npx --yes @openai/codex plugin marketplace list
|
|
70
|
+
npx --yes @openai/codex plugin list --available --json # add -m <marketplace> to scope
|
|
68
71
|
```
|
|
69
72
|
|
|
73
|
+
> **Lane-state reporting (mandatory).** Neither CLI supports a keyword query, and both see only
|
|
74
|
+
> *configured* marketplaces. Record each lane as `EXECUTED` / `EMPTY` / `FAILED: <stderr>` and carry
|
|
75
|
+
> that state into the recommendation. **A `FAILED` lane must never be rendered as "no candidates"** —
|
|
76
|
+
> re-run it or fall back to Priority 3 web search before reporting an empty result.
|
|
77
|
+
|
|
70
78
|
**npm ecosystem search (scoped packages):**
|
|
71
79
|
```bash
|
|
72
80
|
npm search @chrono-meta [keyword]
|
|
@@ -113,11 +121,20 @@ If either duplicate condition met → skip install → report "Already active"
|
|
|
113
121
|
#### 5-1 through 5-3. Install Steps
|
|
114
122
|
|
|
115
123
|
1. Confirm intent: "Would you like to install the `[plugin-name]` plugin?"
|
|
116
|
-
2. On agreement
|
|
124
|
+
2. On agreement — **the two commands take different arguments**: `marketplace add` takes a *source*
|
|
125
|
+
(`<owner/repo>`, a URL, or a local path), never a plugin name; only `install` takes the plugin name.
|
|
117
126
|
```bash
|
|
118
|
-
claude plugin marketplace add [
|
|
119
|
-
|
|
127
|
+
# Usage: claude plugin marketplace add [options] SOURCE
|
|
128
|
+
# SOURCE = owner/repo, a URL, or a local path — NEVER a plugin name
|
|
129
|
+
SOURCE="owner/repo"
|
|
130
|
+
PLUGIN="plugin-name" # optionally "plugin-name@marketplace" to disambiguate
|
|
131
|
+
|
|
132
|
+
claude plugin marketplace add "$SOURCE"
|
|
133
|
+
# Usage: claude plugin install|i [options] PLUGIN
|
|
134
|
+
claude plugin install "$PLUGIN"
|
|
120
135
|
```
|
|
136
|
+
Skip the `marketplace add` line when the plugin already resolves from a configured marketplace
|
|
137
|
+
(check `claude plugin marketplace list`).
|
|
121
138
|
3. Post-install initial configuration guidance:
|
|
122
139
|
- **API token input**: Guide token generation path for external service APIs (Jira/Confluence/Slack — specify each service's token page URL + env var or plugin config storage location)
|
|
123
140
|
- **MCP connection**: If plugin uses MCP server, guide auto-update of `.mcp.json` or `claude mcp add` command
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: prompt-regression
|
|
3
|
-
description:
|
|
3
|
+
description: Statically checks harness assets against a known-answer probe set after rule/skill changes — inspects the changed source for the trigger phrases, chain links and gate conditions each probe expects, and reports PASS/FAIL/SKIP per probe. Source inspection only; it does not run live sessions, so it catches assets that no longer SAY the right thing, not models that stop DOING it. Triggers on "prompt regression", "did my changes break anything", "regression check", "test harness changes".
|
|
4
4
|
user-invocable: true
|
|
5
|
-
allowed-tools: ["Read", "Bash", "Glob", "Grep"]
|
|
5
|
+
allowed-tools: ["Read", "Write", "Bash", "Glob", "Grep"]
|
|
6
6
|
model: sonnet
|
|
7
7
|
complexity_routing:
|
|
8
8
|
base: sonnet
|
|
@@ -58,8 +58,15 @@ ls .claude/regression/probes.md 2>/dev/null || echo "NO_CUSTOM_PROBES"
|
|
|
58
58
|
```
|
|
59
59
|
|
|
60
60
|
**If custom probes exist**: load and use them. The hub repo ships its golden probe set
|
|
61
|
-
(known-answer offline eval,
|
|
62
|
-
|
|
61
|
+
(known-answer offline eval, **33 probes** with check classes — 27 mandatory-pass · 1 measured ·
|
|
62
|
+
5 judged, of which 2 rows are inert deletion anchors, so live coverage is 31) at exactly this path
|
|
63
|
+
— when present it is canonical and supersedes the default matrix below.
|
|
64
|
+
|
|
65
|
+
> Count from the file, not from this line: `grep -cE '^\| *`[A-Z][A-Z0-9-]*-[0-9]+` *\|'
|
|
66
|
+
> .claude/regression/probes.md`. Both this number and the tally inside `probes.md` read `32` until
|
|
67
|
+
> 2026-08-12, when the actual count was 33 — a probe had been added to section A without touching
|
|
68
|
+
> either summary. A count duplicated in two files rots independently; if the two disagree, the file
|
|
69
|
+
> wins and both get corrected.
|
|
63
70
|
|
|
64
71
|
**If no custom probes** (e.g. Mode C install without the hub repo): use the default
|
|
65
72
|
probe matrix below.
|
|
@@ -93,7 +100,23 @@ If change scope is `CLAUDE.md` core (10+ lines changed): run **full suite** (all
|
|
|
93
100
|
|
|
94
101
|
---
|
|
95
102
|
|
|
96
|
-
### Step 4.
|
|
103
|
+
### Step 4. Evaluate Affected Probes (static source inspection)
|
|
104
|
+
|
|
105
|
+
**What this step is, stated plainly.** Every check below reads the changed *source* and asks whether
|
|
106
|
+
the text a probe expects is still there. No live session is started, no model is prompted, no output
|
|
107
|
+
is compared against a recorded transcript. The description said "running standard prompt probes …
|
|
108
|
+
comparing outputs against saved baselines", which reads as live execution; the honest label is a
|
|
109
|
+
**known-answer static check**.
|
|
110
|
+
|
|
111
|
+
**What it therefore cannot catch** — say this in the report, do not leave it implied:
|
|
112
|
+
- a rule that is still present but has stopped *firing* (salience loss, ordering, competition
|
|
113
|
+
from another rule)
|
|
114
|
+
- a trigger phrase present in the file but shadowed by a higher-priority route
|
|
115
|
+
- any behavior change that leaves the source text identical
|
|
116
|
+
|
|
117
|
+
Those need a dispatched blind sim at the target tier (`sim-conductor`, or the target-tier sim gate in
|
|
118
|
+
`.claude/rules/fh_4axis_gate.md`). A green report here means *the assets still say the right thing*.
|
|
119
|
+
Treating it as behavioral evidence is the misread this section exists to prevent.
|
|
97
120
|
|
|
98
121
|
For each affected probe, evaluate:
|
|
99
122
|
|
|
@@ -150,24 +173,44 @@ If all probes pass:
|
|
|
150
173
|
|
|
151
174
|
After a deliberate behavior change (not a regression — an intentional improvement), update the baseline:
|
|
152
175
|
|
|
176
|
+
Prompt user first: *"Probe `G-GATE-03` now expects the new gate format. Update baseline? (y/n)"*
|
|
177
|
+
Only update on explicit `y` — never auto-update.
|
|
178
|
+
|
|
179
|
+
On `y`, actually perform the write. The previous version of this step was three lines of which two
|
|
180
|
+
were comments — it created the directory and stopped, so "baseline updated" was reported by a step
|
|
181
|
+
that had written nothing.
|
|
182
|
+
|
|
153
183
|
```bash
|
|
154
|
-
# Baseline stored as markdown in .claude/regression/
|
|
155
184
|
mkdir -p .claude/regression
|
|
156
|
-
# Write updated probe expectations
|
|
157
185
|
```
|
|
158
186
|
|
|
159
|
-
|
|
187
|
+
Then **use the `Write` tool** on `.claude/regression/probes.md` (create it from the SKILL.md default
|
|
188
|
+
matrix if absent) to apply the approved edit. Each approved change edits the probe's row in place —
|
|
189
|
+
Expected Behavior, Scope, and Class — and:
|
|
160
190
|
|
|
161
|
-
|
|
191
|
+
- update the `**Count**:` tally line **in the same edit** if a row was added or removed, including
|
|
192
|
+
the per-section breakdown and the class counts (a stale tally is exactly how the `32`/`33`
|
|
193
|
+
mismatch was introduced)
|
|
194
|
+
- append a one-line note under `**Baseline**:` recording the date and the reason for the change
|
|
195
|
+
- never rewrite rows the user did not approve
|
|
196
|
+
|
|
197
|
+
Confirm afterwards by re-reading the file and reporting the row's new content plus the recount —
|
|
198
|
+
`grep -cE '^\| *`[A-Z][A-Z0-9-]*-[0-9]+` *\|' .claude/regression/probes.md`. Do not report a
|
|
199
|
+
baseline update whose result you have not read back.
|
|
162
200
|
|
|
163
201
|
---
|
|
164
202
|
|
|
165
203
|
## Done When
|
|
166
204
|
|
|
167
|
-
- All affected probes are evaluated (PASS / FAIL / SKIP)
|
|
205
|
+
- All affected probes are evaluated (PASS / FAIL / SKIP) and the three counts sum to the number of
|
|
206
|
+
probes selected in Step 3 — class: measured (`PASS + FAIL + SKIP == selected`)
|
|
168
207
|
- Regression report is output with clear PASS/FAIL verdict — class: mandatory-pass
|
|
208
|
+
- The report states its own scope: **static source inspection, no live session run** — a green
|
|
209
|
+
verdict is never presented as behavioral evidence — class: mandatory-pass
|
|
169
210
|
- If FAIL: specific file + line fix is recommended — class: judged, paired with verify-bidirectional (the fix recommendation is re-checked, not trusted as-is)
|
|
170
|
-
- Baseline updated only on explicit user approval
|
|
211
|
+
- Baseline updated only on explicit user approval, and the written file is **read back** and its
|
|
212
|
+
probe count reported — class: mandatory-pass (HITL). Approval alone does not close this: a step
|
|
213
|
+
that prompts, gets `y`, and writes nothing satisfied the old wording.
|
|
171
214
|
|
|
172
215
|
---
|
|
173
216
|
|