@chrono-meta/fh-gate 1.4.73 → 1.4.75
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/CHEATSHEET.md +1 -1
- package/CLAUDE.md +14 -1
- package/docs/ETHOS.md +106 -0
- package/docs/OUTPUT_EVIDENCE.md +118 -0
- package/docs/WHY.md +42 -0
- package/knowledge/patterns/ensemble_union_detection_task_pattern.md +125 -0
- package/knowledge/shared/GLOSSARY.md +77 -0
- package/knowledge/shared/harness-core/harness_frontier_diagnosis_2026-06-02.md +1 -1
- package/knowledge/shared/harness-core/meta_harness_engineering_definition.md +1 -1
- package/knowledge/shared/learnings/subagent_invocations_log.yaml +9 -0
- package/knowledge/shared/patterns/multi-persona-review.md +88 -0
- package/knowledge/shared/plugin-catalog/recommended_plugins.md +117 -0
- package/package.json +28 -1
- package/plugins/fh-commons/.claude-plugin/plugin.json +1 -1
- package/plugins/fh-meta/.claude-plugin/plugin.json +2 -2
- package/plugins/fh-meta/CHANGELOG.md +617 -0
- package/scripts/below_floor_scan.sh +91 -0
- package/scripts/chamber_run.sh +184 -0
- package/scripts/degrade_direction_scan.sh +17 -2
- package/scripts/fh_env_delta_scan.sh +108 -0
- package/scripts/memory_link_check.py +237 -0
- package/scripts/memory_nearcheck.py +131 -0
- package/scripts/package_coverage_check.sh +140 -0
- package/scripts/selfcheck.sh +47 -0
- package/scripts/session_close_check.sh +31 -1
- package/scripts/sidecar_wait.sh +76 -0
- package/scripts/substrate_jump_detector.sh +60 -0
- package/scripts/test_card_drift_probe.sh +77 -0
- package/scripts/test_degrade_scan_shell_probes.sh +26 -0
- package/scripts/test_marker_floor_lanes.sh +45 -0
- package/scripts/test_memory_link_check.sh +134 -0
- package/scripts/test_session_close_lanes.sh +99 -0
- package/scripts/tier_census_grep.sh +54 -0
- package/templates/.claude/rules/session.md +153 -0
- package/templates/contrib_session.md +34 -0
- package/templates/degrade_direction_scan.sh +17 -2
- package/templates/goal-quench-hook-setup.md +152 -0
- package/templates/starter_profile.md +83 -0
- package/templates/temper_check.sh +46 -0
- package/plugins/fh-meta/skills/context-bridge-dispatch/SKILL.md +0 -32
- package/plugins/fh-meta/skills/self-marketing-lint/SKILL.md +0 -30
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# test_marker_floor_lanes.sh — regression fixtures for pre-commit validate_marker_floor lanes.
|
|
3
|
+
#
|
|
4
|
+
# Ships with the 2026-07-10 sonnet-floor lane (Sonnet-Floor Doctrine): each closed hole gets a
|
|
5
|
+
# mechanical regression test (Field-Harness Load-Bearing Change Gate convergence condition).
|
|
6
|
+
# Fixtures assert BOTH directions: the new lane admits exactly its intended shape, and every
|
|
7
|
+
# pre-existing guard still blocks (no degrade-toward-permissive regression).
|
|
8
|
+
#
|
|
9
|
+
# Usage: bash scripts/test_marker_floor_lanes.sh Exit: 0 = all fixtures behave; 1 = regression.
|
|
10
|
+
|
|
11
|
+
set -uo pipefail
|
|
12
|
+
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
|
|
13
|
+
HOOK="$REPO_ROOT/templates/.git-hooks/pre-commit"
|
|
14
|
+
T=$(mktemp -d); trap 'rm -rf "$T"' EXIT
|
|
15
|
+
|
|
16
|
+
sed -n '/^marker_recreate_hint()/,/^}/p;/^validate_marker_floor()/,/^}/p' "$HOOK" > "$T/fn.sh"
|
|
17
|
+
|
|
18
|
+
run() { bash -c "source '$T/fn.sh'; validate_marker_floor '$1'" >/dev/null 2>&1; }
|
|
19
|
+
|
|
20
|
+
FAIL=0
|
|
21
|
+
check() { # $1=fixture $2=expected(PASS|BLOCK) $3=label
|
|
22
|
+
if run "$1"; then got=PASS; else got=BLOCK; fi
|
|
23
|
+
if [ "$got" = "$2" ]; then echo "✅ $3 → $got"; else echo "❌ $3 → $got (expected $2)"; FAIL=1; fi
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
printf 'axis2-engine: inline\naxis2-model: sonnet\nfloor-status: sonnet-floor\naxis2-anchor: regression test 5/5 pass\naxis2-evidence: PASS no-S, 2B applied\n' > "$T/m1"
|
|
27
|
+
printf 'axis2-engine: inline\naxis2-model: sonnet\nfloor-status: sonnet-floor\naxis2-evidence: PASS no-S\n' > "$T/m2"
|
|
28
|
+
printf 'axis2-engine: inline\naxis2-model: haiku\nfloor-status: sonnet-floor\naxis2-anchor: probe 3/3\naxis2-evidence: PASS no-S\n' > "$T/m3"
|
|
29
|
+
printf 'axis2-engine: inline\naxis2-model: sonnet\nfloor-status: at-floor\naxis2-evidence: PASS no-S\n' > "$T/m4"
|
|
30
|
+
printf 'axis2-engine: inline\naxis2-model: haiku\nfloor-status: below-floor\naxis2-evidence: PASS no-S\n' > "$T/m5"
|
|
31
|
+
printf 'axis2-engine: quench-challenger\naxis2-model: opus\nfloor-status: at-floor\naxis2-evidence: 1S/4A fixed\n' > "$T/m6"
|
|
32
|
+
printf 'axis2-engine: inline\naxis2-model: haiku\nfloor-status: below-floor\nbelow-floor-ack: "approved, proceed" — canary-only change\naxis2-evidence: PASS no-S\n' > "$T/m7"
|
|
33
|
+
printf 'axis2-engine: inline\naxis2-model: opus\nfloor-status: bogus-status\naxis2-evidence: PASS\n' > "$T/m8"
|
|
34
|
+
|
|
35
|
+
check "$T/m1" PASS "sonnet-floor + anchor + sonnet model (new lane, intended shape)"
|
|
36
|
+
check "$T/m2" BLOCK "sonnet-floor WITHOUT anchor (anchor is the compensating requirement)"
|
|
37
|
+
check "$T/m3" BLOCK "haiku claiming sonnet-floor (lane mislabel)"
|
|
38
|
+
check "$T/m4" BLOCK "sonnet claiming at-floor (2026-06-10 mislabel class — guard intact)"
|
|
39
|
+
check "$T/m5" BLOCK "below-floor without ack (guard intact)"
|
|
40
|
+
check "$T/m6" PASS "opus at-floor (legacy lane intact)"
|
|
41
|
+
check "$T/m7" PASS "below-floor with quoted ack (legacy lane intact)"
|
|
42
|
+
check "$T/m8" BLOCK "invalid floor-status (fail-closed on unknown value)"
|
|
43
|
+
|
|
44
|
+
[ "$FAIL" -eq 0 ] && echo "── all marker-floor lane fixtures behave ──"
|
|
45
|
+
exit "$FAIL"
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# test_memory_link_check.sh — known-pair anchor for scripts/memory_link_check.py.
|
|
3
|
+
#
|
|
4
|
+
# WHY: the checker's --fix-separators path WRITES to personal knowledge files. Everything it gets
|
|
5
|
+
# wrong, it gets wrong silently and in bulk. Two of its rules were found only by attacking it:
|
|
6
|
+
# * a first draft rewrote links inside FENCED blocks — i.e. it "corrected" the examples that
|
|
7
|
+
# document the convention, which is the probe-damages-the-remedy class;
|
|
8
|
+
# * a first measurement counted cross-store links as broken, overstating the defect by 44%.
|
|
9
|
+
# Both are pinned below, alongside the classes.
|
|
10
|
+
#
|
|
11
|
+
# Lanes
|
|
12
|
+
# C1 the five classes separate on a fixture (ok / separator / cross-store-absent / placeholder / dangling)
|
|
13
|
+
# F1 a link inside a fenced block is COUNTED but never REWRITTEN
|
|
14
|
+
# F2 a link inside inline backticks IS rewritten (this corpus styles real links that way —
|
|
15
|
+
# measured 2026-07-28: 25 such links repaired, 0 fenced changes in the same run)
|
|
16
|
+
# F3 aliased links [[target|alias]] keep their alias
|
|
17
|
+
# F4 re-running the fixer changes nothing (idempotent)
|
|
18
|
+
# G1 an empty store reports an extractor failure, never a clean graph
|
|
19
|
+
#
|
|
20
|
+
# Exit 0 = 6/6.
|
|
21
|
+
set -uo pipefail
|
|
22
|
+
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
23
|
+
CHK="$ROOT/scripts/memory_link_check.py"
|
|
24
|
+
[ -f "$CHK" ] || { echo "FAIL: $CHK missing"; exit 1; }
|
|
25
|
+
|
|
26
|
+
pass=0; fail=0
|
|
27
|
+
ok() { printf ' ✅ %s\n' "$1"; pass=$((pass+1)); }
|
|
28
|
+
bad() { printf ' ❌ %s\n' "$1"; fail=$((fail+1)); }
|
|
29
|
+
|
|
30
|
+
TD="$(mktemp -d)"; trap 'rm -rf "$TD"' EXIT
|
|
31
|
+
mkdir -p "$TD/store"
|
|
32
|
+
printf -- '---\nname: real_target\n---\nbody\n' > "$TD/store/real_target.md"
|
|
33
|
+
cat > "$TD/store/src.md" <<'EOF'
|
|
34
|
+
---
|
|
35
|
+
name: src
|
|
36
|
+
---
|
|
37
|
+
plain ok: [[real_target]]
|
|
38
|
+
plain separator: [[real-target]]
|
|
39
|
+
alias: [[real-target|shown as this]]
|
|
40
|
+
inline: `[[real-target]]`
|
|
41
|
+
dangling: [[nothing_here]]
|
|
42
|
+
placeholder: [[link]]
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
fenced example — must NOT be rewritten: [[real-target]]
|
|
46
|
+
```
|
|
47
|
+
EOF
|
|
48
|
+
|
|
49
|
+
_run() { python3 "$CHK" --memory "$TD/store" "$@" 2>/dev/null; }
|
|
50
|
+
|
|
51
|
+
out=$(_run)
|
|
52
|
+
# FIRST match only. `dangling` appears twice in the report — once as a count row and once as a
|
|
53
|
+
# section header ("dangling (nothing on disk...)") — so an unbounded match returned two lines and
|
|
54
|
+
# the numeric comparison silently failed against a correct tool. Instrument fault, fixed here.
|
|
55
|
+
_n() { printf '%s\n' "$out" | awk -v k="$1" '$1==k && $2 ~ /^[0-9]+$/ {print $2; exit}'; }
|
|
56
|
+
if [ "$(_n ok)" = "1" ] && [ "$(_n placeholder)" = "1" ] && [ "$(_n dangling)" = "1" ] && [ "$(_n separator)" -ge 4 ]; then
|
|
57
|
+
ok "C1 classes separate (ok=$(_n ok) separator=$(_n separator) placeholder=$(_n placeholder) dangling=$(_n dangling))"
|
|
58
|
+
else
|
|
59
|
+
bad "C1 class counts wrong"; printf '%s\n' "$out" | sed 's/^/ /'
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
_run --fix-separators --quiet >/dev/null
|
|
63
|
+
body=$(cat "$TD/store/src.md")
|
|
64
|
+
|
|
65
|
+
if printf '%s' "$body" | sed -n '/```/,/```/p' | grep -q '\[\[real-target\]\]'; then
|
|
66
|
+
ok "F1 fenced example left untouched (the documentation of the rule survives the fixer)"
|
|
67
|
+
else
|
|
68
|
+
bad "F1 the fixer rewrote a link inside a fenced block — it corrected its own example"
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
if printf '%s' "$body" | grep -q 'inline: `\[\[real_target\]\]`'; then
|
|
72
|
+
ok "F2 inline-backticked link repaired (this store's citation style is a real link)"
|
|
73
|
+
else
|
|
74
|
+
bad "F2 inline-backticked link was not repaired"
|
|
75
|
+
fi
|
|
76
|
+
|
|
77
|
+
if printf '%s' "$body" | grep -q '\[\[real_target|shown as this\]\]'; then
|
|
78
|
+
ok "F3 alias preserved through the rewrite"
|
|
79
|
+
else
|
|
80
|
+
bad "F3 alias lost or target not rewritten"
|
|
81
|
+
fi
|
|
82
|
+
|
|
83
|
+
before=$(cat "$TD/store/src.md")
|
|
84
|
+
_run --fix-separators --quiet >/dev/null
|
|
85
|
+
if [ "$before" = "$(cat "$TD/store/src.md")" ]; then
|
|
86
|
+
ok "F4 idempotent on re-run"
|
|
87
|
+
else
|
|
88
|
+
bad "F4 a second run changed the file again"
|
|
89
|
+
fi
|
|
90
|
+
|
|
91
|
+
mkdir -p "$TD/empty"
|
|
92
|
+
if python3 "$CHK" --memory "$TD/empty" >/dev/null 2>&1; then
|
|
93
|
+
bad "G1 an empty store exited 0 — a scan that cannot see its subject reported a clean graph"
|
|
94
|
+
else
|
|
95
|
+
ok "G1 empty store fails as an extractor error, not a pass"
|
|
96
|
+
fi
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
# H1/A1 — cross-family findings, both confirmed by execution before acceptance.
|
|
100
|
+
# H1 (agy): an anchor-form link `[[target#section]]` was COUNTED as repairable but the rewrite
|
|
101
|
+
# enumerated closing forms by hand and never matched it — so it was flagged on every
|
|
102
|
+
# run (idempotence broken) and the summary reported more fixes than it made.
|
|
103
|
+
# A1 (gpt-5.5): two notes sharing a normalized name let the fixer reroute an edge to whichever
|
|
104
|
+
# sorted first, and the wrong link then resolves exactly, so no later run flags it.
|
|
105
|
+
printf -- '---\nname: my_topic\n---\nbody\n' > "$TD/store/my_topic.md"
|
|
106
|
+
printf -- '---\nname: anchored\n---\nanchor: [[my-topic#section-1]]\nplain: [[my-topic]]\n' > "$TD/store/anchored.md"
|
|
107
|
+
_run --fix-separators --quiet >/dev/null
|
|
108
|
+
if grep -q '\[\[my_topic#section-1\]\]' "$TD/store/anchored.md"; then
|
|
109
|
+
ok "H1 anchor-form link rewritten (target only, #section preserved)"
|
|
110
|
+
else
|
|
111
|
+
bad "H1 [[target#anchor]] left unrewritten — flagged forever, and the fix count over-reports"
|
|
112
|
+
fi
|
|
113
|
+
# Idempotence here is a STABLE count, not zero: the fenced example is counted every run and
|
|
114
|
+
# deliberately never rewritten, so zero is unreachable by design. Asserting zero was an instrument
|
|
115
|
+
# error in this anchor's first draft — it scored a correct tool as failing.
|
|
116
|
+
before_n=$(out=$(_run); printf '%s\n' "$out" | awk '$1=="separator" && $2 ~ /^[0-9]+$/ {print $2; exit}')
|
|
117
|
+
_run --fix-separators --quiet >/dev/null
|
|
118
|
+
after_n=$(out=$(_run); printf '%s\n' "$out" | awk '$1=="separator" && $2 ~ /^[0-9]+$/ {print $2; exit}')
|
|
119
|
+
if [ "$before_n" = "$after_n" ]; then
|
|
120
|
+
ok "H1b idempotent with anchor forms present (count stable at $after_n — the fenced example)"
|
|
121
|
+
else
|
|
122
|
+
bad "H1b count moved $before_n → $after_n across a second fix pass"
|
|
123
|
+
fi
|
|
124
|
+
printf -- 'A\n' > "$TD/store/collide-x.md"; printf -- 'B\n' > "$TD/store/collide_x.md"
|
|
125
|
+
out=$(_run)
|
|
126
|
+
if printf '%s\n' "$out" | grep -q 'ambiguous'; then
|
|
127
|
+
ok "A1 colliding normalized names surface as a reported class"
|
|
128
|
+
else
|
|
129
|
+
bad "A1 no ambiguous class — a colliding pair can still be auto-rerouted"
|
|
130
|
+
fi
|
|
131
|
+
|
|
132
|
+
echo "----"
|
|
133
|
+
echo "memory-link-check anchor: $pass passed, $fail failed"
|
|
134
|
+
[ "$fail" -eq 0 ] || exit 1
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# test_session_close_lanes.sh — known-pair anchor for session_close_check.sh ② (harvest-loop
|
|
3
|
+
# obligation) and ⑤ (card-last invariant).
|
|
4
|
+
#
|
|
5
|
+
# WHY (2026-07-28): ② used to be an UNSATISFIABLE warning — it fired whenever an FH asset was
|
|
6
|
+
# touched today and the script had no way to observe whether harvest-loop ran, so no session could
|
|
7
|
+
# ever discharge it. A line that fires on every healthy close is noise, and noise trains the runner
|
|
8
|
+
# to skim past the ❌ lines that matter. The repair gave it a mechanical discharge (a harvest-loop
|
|
9
|
+
# decision recorded in TODAY's fh_completed file). This file is that repair's regression anchor:
|
|
10
|
+
# the fix is only real if the ⚠️ still fires when NOTHING is recorded, and stops firing when it is.
|
|
11
|
+
#
|
|
12
|
+
# Lanes (each is a decision the gate must get right, not a smoke test):
|
|
13
|
+
# ②-N FH asset touched today, no harvest-loop line anywhere → ⚠️ MUST fire
|
|
14
|
+
# ②-P1 same, plus "harvest-loop 실행 완료" → ✅ must NOT fire
|
|
15
|
+
# ②-P2 same, plus an explicit SKIP note → ✅ must NOT fire
|
|
16
|
+
# (CLAUDE.md ② accepts "harvest-loop (or an explicit skip note)" — a recorded skip is
|
|
17
|
+
# a discharged obligation, not an evaded one)
|
|
18
|
+
# ②-C no FH asset touched today → neither line appears at all
|
|
19
|
+
# (over-firing is a defect in its own right — the whole reason this repair exists)
|
|
20
|
+
# ⑤-N a close artifact newer than the card → ❌ card-last MUST fire (exit 1)
|
|
21
|
+
# ⑤-P card is the newest artifact → ✅ card-last holds
|
|
22
|
+
#
|
|
23
|
+
# Exit 0 = 7/7 lanes calibrated · exit 1 = the gate's instrument is wrong (do not trust its verdict)
|
|
24
|
+
|
|
25
|
+
set -uo pipefail
|
|
26
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
27
|
+
CHECK="$SCRIPT_DIR/session_close_check.sh"
|
|
28
|
+
TODAY=$(date +%Y-%m-%d)
|
|
29
|
+
FAILED=0
|
|
30
|
+
|
|
31
|
+
if [ ! -f "$CHECK" ]; then
|
|
32
|
+
echo "FAIL session-close lanes: subject $CHECK missing"
|
|
33
|
+
exit 1
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
# Builds a throwaway repo whose HEAD commit touches (or does not touch) an FH asset path.
|
|
37
|
+
_fixture() { # $1=touch_fh_asset(0/1) $2=completed-file body (empty = no file)
|
|
38
|
+
local touch_fh="$1" body="$2" T
|
|
39
|
+
T=$(mktemp -d)
|
|
40
|
+
( cd "$T" \
|
|
41
|
+
&& git init -q . \
|
|
42
|
+
&& git config user.email anchor@local && git config user.name anchor \
|
|
43
|
+
&& if [ "$touch_fh" = 1 ]; then echo x > CLAUDE.md; else echo x > unrelated.txt; fi \
|
|
44
|
+
&& git add -A && git commit -qm "fixture" ) >/dev/null 2>&1
|
|
45
|
+
mkdir -p "$T/tracks/_meta"
|
|
46
|
+
[ -n "$body" ] && printf '%s\n' "$body" > "$T/tracks/_meta/fh_completed_${TODAY}.md"
|
|
47
|
+
printf '# card\n' > "$T/tracks/_meta/reference_next_session_starter.md"
|
|
48
|
+
printf '%s' "$T"
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
_lane() { # $1=name $2=grep-pattern $3=expect(0/1) $4=fixture dir
|
|
52
|
+
local name="$1" pat="$2" expect="$3" T="$4" out hit
|
|
53
|
+
out=$(bash "$CHECK" "$T" 2>/dev/null)
|
|
54
|
+
hit=0
|
|
55
|
+
printf '%s\n' "$out" | grep -q "$pat" && hit=1
|
|
56
|
+
rm -rf "$T"
|
|
57
|
+
if [ "$hit" = "$expect" ]; then
|
|
58
|
+
echo "✅ $name (hit=$hit, expected=$expect)"
|
|
59
|
+
else
|
|
60
|
+
echo "❌ $name — hit=$hit, expected=$expect"
|
|
61
|
+
printf '%s\n' "$out" | sed 's/^/ /'
|
|
62
|
+
FAILED=1
|
|
63
|
+
fi
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
WARN2='⚠️ ② FH assets changed today'
|
|
67
|
+
OK2='✅ ② FH assets changed today'
|
|
68
|
+
|
|
69
|
+
_lane "②-N no harvest-loop decision recorded → warns" "$WARN2" 1 "$(_fixture 1 '- 항목 하나')"
|
|
70
|
+
_lane "②-P1 harvest-loop run recorded → silent" "$WARN2" 0 "$(_fixture 1 '- harvest-loop 실행 완료')"
|
|
71
|
+
_lane "②-P2 explicit skip note → silent" "$WARN2" 0 "$(_fixture 1 '- harvest-loop: skipped — 3-repo session, deferred')"
|
|
72
|
+
_lane "②-P1 run recorded → prints the ✅ form" "$OK2" 1 "$(_fixture 1 '- harvest-loop 실행 완료')"
|
|
73
|
+
_lane "②-C no FH asset touched → no ② line at all" ' ② ' 0 "$(_fixture 0 '- 항목 하나')"
|
|
74
|
+
|
|
75
|
+
# ⑤ card-last: an artifact newer than the card is the bug class the invariant exists to catch.
|
|
76
|
+
T=$(_fixture 1 '- harvest-loop 실행 완료')
|
|
77
|
+
touch "$T/tracks/_meta/fh_completed_${TODAY}.md" # make it strictly newer than the card
|
|
78
|
+
if bash "$CHECK" "$T" >/dev/null 2>&1; then
|
|
79
|
+
echo "❌ ⑤-N artifact newer than card → expected exit 1, got 0 (card-last not enforced)"
|
|
80
|
+
FAILED=1
|
|
81
|
+
else
|
|
82
|
+
echo "✅ ⑤-N artifact newer than card → exit 1 (card-last enforced)"
|
|
83
|
+
fi
|
|
84
|
+
touch "$T/tracks/_meta/reference_next_session_starter.md" # card becomes newest
|
|
85
|
+
if bash "$CHECK" "$T" >/dev/null 2>&1; then
|
|
86
|
+
echo "✅ ⑤-P card newest → exit 0"
|
|
87
|
+
else
|
|
88
|
+
echo "❌ ⑤-P card newest → expected exit 0, got 1 (over-blocking: trains --no-verify)"
|
|
89
|
+
bash "$CHECK" "$T" 2>&1 | sed 's/^/ /'
|
|
90
|
+
FAILED=1
|
|
91
|
+
fi
|
|
92
|
+
rm -rf "$T"
|
|
93
|
+
|
|
94
|
+
if [ "$FAILED" -ne 0 ]; then
|
|
95
|
+
echo "SESSION-CLOSE LANES: FAIL — the gate's instrument is miscalibrated"
|
|
96
|
+
exit 1
|
|
97
|
+
fi
|
|
98
|
+
echo "SESSION-CLOSE LANES: PASS (7/7)"
|
|
99
|
+
exit 0
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# tier_census_grep.sh — word-boundary tier-reference census helper (Sonnet-Floor Doctrine).
|
|
3
|
+
#
|
|
4
|
+
# WHY (origin: fh_signal_2026-07-10_session — Sonnet full-loop probe): the naive census pattern
|
|
5
|
+
# `opus|sonnet|haiku|floor|tier|model:` false-positives heavily ("frontier" matches `tier`,
|
|
6
|
+
# "floors" prose, method-sense "model"). The probe self-corrected, but per the doctrine's own
|
|
7
|
+
# prescription ladder (step 1: mechanize) the discipline belongs in a script, not re-derived
|
|
8
|
+
# per session. Built 2026-07-10 on operator instruction (evidence-threshold overridden by
|
|
9
|
+
# explicit "complete it" — recorded, not silent).
|
|
10
|
+
#
|
|
11
|
+
# WHAT: emits candidate tier-reference hits with word-boundary patterns, one line per hit
|
|
12
|
+
# (file:line:text), for the auditor to CLASSIFY per sonnet_floor_doctrine.md's table
|
|
13
|
+
# (trust-floor / availability-gate / advisory / N-A). The script finds candidates; the
|
|
14
|
+
# classification stays a judged step with the doctrine table as its anchor.
|
|
15
|
+
#
|
|
16
|
+
# Sense-filter hints (printed, not auto-applied — de-noising must never hide a real gate):
|
|
17
|
+
# - "frontier|multi-tier|C-tier|A/B-tier" → usually N/A (different axis: content/data tiers)
|
|
18
|
+
# - "hub model|mental model|data model" → usually N/A (methodology sense of "model")
|
|
19
|
+
# - execution tier S/M/L/XL → N/A (token budget, not model tier — fh_detail_protocols)
|
|
20
|
+
#
|
|
21
|
+
# Usage: bash scripts/tier_census_grep.sh <file> [file...] Exit: 0 always (census, not gate)
|
|
22
|
+
|
|
23
|
+
set -uo pipefail
|
|
24
|
+
|
|
25
|
+
if [ $# -eq 0 ]; then
|
|
26
|
+
echo "usage: bash scripts/tier_census_grep.sh <file> [file...]" >&2
|
|
27
|
+
exit 0
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
PATTERN='\b(opus|sonnet|haiku|fable)\b|\bfloor(-status|-tier|s)?\b|\btiers?\b|(^|[^a-zA-Z])model:'
|
|
31
|
+
|
|
32
|
+
for f in "$@"; do
|
|
33
|
+
if [ ! -f "$f" ]; then
|
|
34
|
+
echo "── $f: NOT FOUND (phantom input — check the path) ──"
|
|
35
|
+
continue
|
|
36
|
+
fi
|
|
37
|
+
echo "── census candidates: $f ──"
|
|
38
|
+
# -P where available (GNU/pcre); BSD grep on macOS supports -E word boundaries via [[:<:]] —
|
|
39
|
+
# portable route: grep -nEi with \b works on GNU; on BSD use perl fallback.
|
|
40
|
+
if echo x | grep -P 'x' >/dev/null 2>&1; then
|
|
41
|
+
grep -nPi "$PATTERN" "$f" || echo " (0 candidates)"
|
|
42
|
+
else
|
|
43
|
+
# 0-hit에도 "(0 candidates)"를 찍는다 — GNU 분기와 출력 대칭 (pmh-parity 포트가 잡은 갭, 역이식 2026-07-10)
|
|
44
|
+
hits=$(perl -ne 'print "$.:$_" if /\b(opus|sonnet|haiku|fable)\b|\bfloor(-status|-tier|s)?\b|\btiers?\b|(^|[^a-zA-Z])model:/i' "$f")
|
|
45
|
+
if [ -n "$hits" ]; then printf '%s\n' "$hits"; else echo " (0 candidates)"; fi
|
|
46
|
+
fi
|
|
47
|
+
done
|
|
48
|
+
|
|
49
|
+
cat <<'HINTS'
|
|
50
|
+
── classify each hit per sonnet_floor_doctrine.md (trust-floor / availability-gate / advisory / N-A) ──
|
|
51
|
+
N/A sense hints (verify, don't auto-drop): frontier·C-tier·A/B-tier (content-tier axis) ·
|
|
52
|
+
"hub/mental/data model" (methodology sense) · S/M/L/XL execution tier (token budget, not model).
|
|
53
|
+
HINTS
|
|
54
|
+
exit 0
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
session.md — Claude Code Session Rules Template
|
|
3
|
+
|
|
4
|
+
Purpose of this file:
|
|
5
|
+
- Define Claude's session operating rules (how to behave)
|
|
6
|
+
- Behavioral guidelines applied across the entire project
|
|
7
|
+
- Commit to Git and share with the team
|
|
8
|
+
- Edited and managed directly by the user
|
|
9
|
+
|
|
10
|
+
Difference from MEMORY.md:
|
|
11
|
+
- MEMORY.md: Stores data/experience learned during conversation (auto-managed by Claude)
|
|
12
|
+
- session.md: Defines procedures/rules for Claude to follow (edited directly by the user)
|
|
13
|
+
|
|
14
|
+
Usage:
|
|
15
|
+
- Copy this file to your project's .claude/rules/session.md
|
|
16
|
+
- Add, remove, or modify sections to fit your project
|
|
17
|
+
- Change sections marked with [CUSTOMIZE] comments to match your project
|
|
18
|
+
-->
|
|
19
|
+
|
|
20
|
+
### Automatic Actions at Session Start
|
|
21
|
+
|
|
22
|
+
#### Root Memory (Knowledge Hub) Connection
|
|
23
|
+
|
|
24
|
+
At the start of a conversation ("hello", "let's start", "load root memory"), perform the following:
|
|
25
|
+
|
|
26
|
+
1. Read `{FH_ROOT}/CATALOG.md`
|
|
27
|
+
- Understand recent work context
|
|
28
|
+
- Check today's tasks (todo/plan)
|
|
29
|
+
|
|
30
|
+
2. Load project memory index
|
|
31
|
+
- Check `.claude/projects/.../memory/MEMORY.md`
|
|
32
|
+
- Prioritize loading memory most relevant to current work
|
|
33
|
+
- Proceed naturally without notifying the user that memory was loaded
|
|
34
|
+
|
|
35
|
+
#### Exceptions
|
|
36
|
+
- If the user explicitly requests not to use memory
|
|
37
|
+
- For simple one-off questions, load is optional
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
### Session Backup Before Tests
|
|
42
|
+
|
|
43
|
+
<!-- [CUSTOMIZE] Adjust trigger conditions to match your test framework -->
|
|
44
|
+
|
|
45
|
+
#### Automatic Backup Trigger
|
|
46
|
+
|
|
47
|
+
At any point when tests could be run, **automatically** perform a session backup:
|
|
48
|
+
|
|
49
|
+
1. **When I recommend running tests** — **immediately before** the recommendation message
|
|
50
|
+
2. **When the user signals intent to start tests** — **before** running the test command
|
|
51
|
+
|
|
52
|
+
#### Why Backup
|
|
53
|
+
- Sessions can be forcibly terminated when tests start
|
|
54
|
+
- Prevents loss of conversation context, analysis results, and change history
|
|
55
|
+
|
|
56
|
+
#### How to Backup
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
cat > .claude/session_backup_$(date +%Y%m%d_%H%M%S).md << 'EOF'
|
|
60
|
+
# Session Backup - [Task Title]
|
|
61
|
+
|
|
62
|
+
## Problem
|
|
63
|
+
- [Issue currently being resolved]
|
|
64
|
+
|
|
65
|
+
## Changes Made
|
|
66
|
+
- [filename:line]
|
|
67
|
+
- [before/after]
|
|
68
|
+
|
|
69
|
+
## Next Steps
|
|
70
|
+
- [Things to verify after tests]
|
|
71
|
+
EOF
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
#### Important
|
|
75
|
+
- Perform **automatically** even without an explicit user request
|
|
76
|
+
- Never recommend tests without first creating a backup
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
### Automatic Response to Issues
|
|
81
|
+
|
|
82
|
+
<!-- [CUSTOMIZE] Adjust report tool/path to match your project -->
|
|
83
|
+
|
|
84
|
+
#### Automatic Check Trigger
|
|
85
|
+
|
|
86
|
+
When the user mentions a problem, **automatically** locate and analyze the latest test report:
|
|
87
|
+
|
|
88
|
+
1. **Trigger keywords**
|
|
89
|
+
- "something broke", "got an error", "it failed", "not working"
|
|
90
|
+
- "issue occurred", "test failed", "broken", "failed"
|
|
91
|
+
|
|
92
|
+
2. **Analyze and report**
|
|
93
|
+
- Names of failing test cases
|
|
94
|
+
- Error messages and stack traces
|
|
95
|
+
- Summarize in a concise format
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
### Code Writing Principles
|
|
100
|
+
|
|
101
|
+
<!-- [CUSTOMIZE] Adjust to match your project's coding conventions. The 5 principles below are universal and valid for any project. -->
|
|
102
|
+
|
|
103
|
+
Be conscious of all 5 principles **before** writing code — directly reduces back-and-forth where Claude rushes to create something and the user has to correct it.
|
|
104
|
+
|
|
105
|
+
#### 1. Reference Existing Code (Consistency First)
|
|
106
|
+
|
|
107
|
+
- **Reference targets**: Code with similar functionality or in the same layer within the project
|
|
108
|
+
- **No introducing new patterns** — follow existing patterns first; only abstract when the same pattern repeats 3+ times and needs consolidation
|
|
109
|
+
- **Follow framework Core/Base class patterns** — if the project has `.claude/rules/`, that hierarchy takes precedence
|
|
110
|
+
|
|
111
|
+
#### 2. Independence and Regression Prevention
|
|
112
|
+
|
|
113
|
+
- Verify that new code **does not break existing tests or functionality**
|
|
114
|
+
- Manage side effects (shared state, global variables, file locks)
|
|
115
|
+
- Use `git grep` before changes to understand the impact surface — check for unexpected callers
|
|
116
|
+
|
|
117
|
+
#### 3. Locator and Identifier Stability (UI code only)
|
|
118
|
+
|
|
119
|
+
<!-- [CUSTOMIZE] Can be removed for non-mobile QA / non-web QA projects -->
|
|
120
|
+
|
|
121
|
+
- Do not depend on dynamically generated attributes (auto-generated id, timestamps in content-desc)
|
|
122
|
+
- Avoid absolute XPath — fragile to structural changes
|
|
123
|
+
- Consider i18n for text-based identifiers (multilingual projects)
|
|
124
|
+
- If the project has `.claude/rules/LOCATOR_*` guides, those take precedence
|
|
125
|
+
|
|
126
|
+
#### 4. Flakiness Risk Management
|
|
127
|
+
|
|
128
|
+
- **No `time.sleep`** — use explicit waits (implicit/explicit wait) + condition-based polling
|
|
129
|
+
- No unbounded waits without a timeout
|
|
130
|
+
- Allow tolerance in screenshot-based assertions
|
|
131
|
+
- Minimize assumptions about device/environment state (keyboard visibility, previous screen state, etc.)
|
|
132
|
+
|
|
133
|
+
#### 5. Mandatory grep Before Design (Prevent Missing Own Assets)
|
|
134
|
+
|
|
135
|
+
**Before** designing a new feature or pattern:
|
|
136
|
+
|
|
137
|
+
1. grep for similar implementations in the project — reuse if already present
|
|
138
|
+
2. grep learnings from sibling projects in the hub (e.g., `{FH_ROOT}/`) — prevent reinventing solutions already solved elsewhere
|
|
139
|
+
3. Re-read the project's CLAUDE.md and rules/*.md — check for overlooked constraints
|
|
140
|
+
|
|
141
|
+
Starting design with zero cited references is a warning signal for **missing own assets**. Always present at least 1 grep result before beginning design.
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
### Rule Hierarchy and Priority
|
|
146
|
+
|
|
147
|
+
<!-- [CUSTOMIZE] Define rule sources and priority for your project -->
|
|
148
|
+
|
|
149
|
+
**Priority when conflicts arise:**
|
|
150
|
+
1. **Framework rules** — code patterns (non-negotiable)
|
|
151
|
+
2. **Test design philosophy** — "what to test" (QA Identity, etc.)
|
|
152
|
+
3. **Learned feedback** — rules based on user experience
|
|
153
|
+
4. **Operational rules** — session backup, report analysis, and other work processes
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: {session title — include the date}
|
|
3
|
+
description: {one-line main achievement or pattern}
|
|
4
|
+
type: contrib-session
|
|
5
|
+
date: YYYY-MM-DD
|
|
6
|
+
tags: [{related}, {tags}]
|
|
7
|
+
contributor: {your-handle}
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# {Session title}
|
|
11
|
+
|
|
12
|
+
<!--
|
|
13
|
+
Consent note: placing this file under tracks/_contrib/ is your consent to publish it.
|
|
14
|
+
De-identify before opening the PR: no employer/internal-project/colleague names, no home paths,
|
|
15
|
+
no internal domains, no credentials. The PR gate re-checks, but you scrub first.
|
|
16
|
+
-->
|
|
17
|
+
|
|
18
|
+
## Context
|
|
19
|
+
|
|
20
|
+
{What project/situation this came from — de-identified. What problem you were working on.}
|
|
21
|
+
|
|
22
|
+
## What happened / what was found
|
|
23
|
+
|
|
24
|
+
{The work, the pattern, the failure, the fix. Concrete enough to be reusable — file/command level
|
|
25
|
+
where possible, minus anything private.}
|
|
26
|
+
|
|
27
|
+
## Why it matters beyond my project
|
|
28
|
+
|
|
29
|
+
{The reusable claim: when would another operator hit this? What does this generalize to?}
|
|
30
|
+
|
|
31
|
+
## Decisions / open questions
|
|
32
|
+
|
|
33
|
+
- Decision: {key call made and why}
|
|
34
|
+
- Open: {what remains unresolved — only if applicable}
|
|
@@ -150,9 +150,24 @@ for f in "${FILES[@]}"; do
|
|
|
150
150
|
# S5 — the pipefail-fallback disarm: `... | grep -c ... || echo 0` appends a SECOND line under
|
|
151
151
|
# `set -o pipefail`, so the later `-gt` integer test becomes a bash error (= false) and the guard
|
|
152
152
|
# passes silently, with the error going only to stderr. Measured class, 2026-07-26.
|
|
153
|
+
#
|
|
154
|
+
# NARROWED 2026-07-28 after hand-verifying all 9 hits this repo produced: 9/9 were false
|
|
155
|
+
# positives, i.e. the probe was pure noise for its own class, and 100% FP trains dismissal of
|
|
156
|
+
# the one hit that will matter. Two distinct causes, both mechanically reproduced:
|
|
157
|
+
# (a) `a || b || echo 0` was read as a pipeline — the old regex could anchor its `\|` on the
|
|
158
|
+
# SECOND bar of the first `||`. No pipe exists, so no second line can ever be produced.
|
|
159
|
+
# (Every `_mtime() { stat -c %Y … || stat -f %m … || echo 0; }` in the tree was flagged.)
|
|
160
|
+
# (b) a real pipeline whose failing stage emits NOTHING (`… | jq -r … || echo 0`) — the
|
|
161
|
+
# fallback then supplies the only line, which is exactly the intended behavior.
|
|
162
|
+
# The disarm needs BOTH a real pipe AND a final stage that emits regardless of upstream failure
|
|
163
|
+
# — a counter (`grep -c`, `wc`). That is the measured shape: `find … | grep -c . || echo 0`
|
|
164
|
+
# yields "9\n0" and the `-gt` guard goes silent. Verified as a known pair (both directions) in
|
|
165
|
+
# scripts/test_degrade_scan_shell_probes.sh; narrowing without that anchor would just trade a
|
|
166
|
+
# noisy probe for a blind one.
|
|
153
167
|
while IFS= read -r m; do
|
|
154
|
-
emit "$f" "${m%%:*}" "S5:pipefail-fallback(sh)" "\`|| echo 0\` fallback on a pipeline — under \`set -o pipefail\`
|
|
155
|
-
done < <(grep -nE '\|[^|]
|
|
168
|
+
emit "$f" "${m%%:*}" "S5:pipefail-fallback(sh)" "\`|| echo 0\` fallback on a pipeline ending in a counter (grep -c/wc) — that stage emits even when an upstream stage fails, so under \`set -o pipefail\` the value gains a SECOND line, the integer comparison errors out, and the guard passes silently; split the pipeline and sanitize to an integer"
|
|
169
|
+
done < <(grep -nE '[^|]\|[[:space:]]*([a-z]+[[:space:]]+)*(grep[^|]*-c|wc)[^|]*\|\|[[:space:]]*echo[[:space:]]+[\"'"'"']?0' "$f" 2>/dev/null \
|
|
170
|
+
| grep -vE '^[0-9]+:[[:space:]]*#' \
|
|
156
171
|
| grep -vE '#[[:space:]]*noqa[:[:space:]]*degrade')
|
|
157
172
|
fi
|
|
158
173
|
|