@chrono-meta/fh-gate 1.4.80 → 1.4.81
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.
|
@@ -11,13 +11,13 @@
|
|
|
11
11
|
"plugins": [
|
|
12
12
|
{
|
|
13
13
|
"name": "fh-meta",
|
|
14
|
-
"version": "1.4.
|
|
14
|
+
"version": "1.4.81",
|
|
15
15
|
"description": "Hub meta-operations toolkit — 35 skills + 7 agents. New in 1.4.53: `fh-codex-doctor` (npm bin) — Codex adapter drift scanner; reads the documented M1/M2/M3 skill tier map + skill/agent source and reports codex-native/adapter-required/claude-native/unclassified per unit, wired into `npm test`/`prepublishOnly` (fail-closed on unclassified Claude-native primitives). New in 1.4.49: steel-quench gains Step 0.6 Verdict-Invariance Probe (groundedness axis — a load-bearing judged gate's verdict must track behavior, not rubric phrasing; measured flip-count over cross-family paraphrases; arXiv:2605.06161 Policy Invariance anchor); multi_model_sidecar_strategy §Vendor-native harness (a model is strongest in its own vendor CLI — Claude/CC, GPT/codex, Gemini/Antigravity; a universal router degrades all of them, so it stays an autocomplete/QA sidecar, never orchestration); predelete_check.sh fail-closed rewrite; memory-hygiene A-TMA anchor. New in 1.4.48: phantom-quench + steel-quench gain external frontier anchors (arXiv:2607.02052 package-hallucination; arXiv:2607.02057 prompt-coverage-adequacy); README model-flat claim reframed from a per-release point-curve to structural invariants (operation flattens across tiers; depth tier-order fixed within a generation). New in 1.4.47: onboarding step ① surfaces the Mode D companion-store session-start load in the auto-read salience anchor (previously only in the local binding + rules, so a greeting could skip the load). New in 1.4.46: context-doctor command-output axis (route to rtk/proxy for verbose CLI stdout, complementing .claudeignore; risk-gated to token-scarce envs). New in 1.4.41: context-doctor 2026 trigger vocab (context engineering/rot/collapse) + phantom-citation hardening; hub measurement-integrity-checklist (cross-model measurement pre-flight: display-name pin/reps≥3/discriminating probe). New in 1.4.40: install-wizard queryable-wiki scaffold (INDEX + session-start read + R/W/C ingest). New in 1.4.39: auto-decorrelation (cross-family verifier sidecar recruitment) + video-ingest (capability-routed video ingestion). New in 1.4.x: verify-axis check-class taxonomy (mandatory-pass/measured/judged), no-reinvention Tier-0 inventory, 7-class failure taxonomy, Destructive-Op Gate, Wave-T (Temper), tier-floor governance, Mode D Model Notice, FC consent lane, default-Sonnet guidance. New in 1.3.0: public-surface-audit, field-harvest Mode B auto-trigger, 4-axis gate scope ext. Validated cross-CLI: Claude Code, Codex, Gemini.",
|
|
16
16
|
"source": "./plugins/fh-meta"
|
|
17
17
|
},
|
|
18
18
|
{
|
|
19
19
|
"name": "fh-commons",
|
|
20
|
-
"version": "1.4.
|
|
20
|
+
"version": "1.4.81",
|
|
21
21
|
"description": "Project-agnostic utility skills — 4 skills (convergence-loop · deliberation · mcp-circuit-breaker · token-budget-gate) + 1 agent (quench-challenger). Domain-independent utilities transplantable into any project.",
|
|
22
22
|
"source": "./plugins/fh-commons"
|
|
23
23
|
}
|
package/package.json
CHANGED
|
@@ -29,6 +29,26 @@
|
|
|
29
29
|
# reflexes on hooks that DO guard irreversible surfaces. Set FH_PIPE_VERDICT_BLOCK=1 to escalate.
|
|
30
30
|
# If the command cannot be extracted, it stays silent: an unparsed input is not a finding.
|
|
31
31
|
#
|
|
32
|
+
# DELIVERY CHANNEL (added 2026-07-31 — closes N=8: detection 100%, delivery 0%)
|
|
33
|
+
# The first shipped version wrote its warning to stderr and exited 0. Per the hook contract
|
|
34
|
+
# (code.claude.com/docs/en/hooks), on exit 0 stderr is IGNORED and stdout is parsed for JSON —
|
|
35
|
+
# so the warning reached the transcript, never the model. The actor making the mistake never saw
|
|
36
|
+
# the guard fire (measured: the guard's own author repeated the guarded mistake twice the day
|
|
37
|
+
# after shipping it, N=7/N=8).
|
|
38
|
+
# Advisory now emits JSON on stdout: `hookSpecificOutput.additionalContext` (wrapped by CC in a
|
|
39
|
+
# system-reminder and injected into MODEL context) + top-level `systemMessage` (shown to the
|
|
40
|
+
# USER). Two audiences, two fields, one emission.
|
|
41
|
+
# ⚠️ `permissionDecision` is DELIBERATELY ABSENT: emitting "allow" alongside the warning would
|
|
42
|
+
# auto-approve the flagged command past the permission system — the guard must never grant what
|
|
43
|
+
# it exists to question. Block mode keeps the exit-2 path (stderr → fed to Claude, call blocked);
|
|
44
|
+
# on exit 2 stdout/JSON is ignored by contract, so stderr is the correct channel there.
|
|
45
|
+
# NAMED RESIDUAL (cross-family, 2026-07-31): with python3 broken/absent, payload extraction
|
|
46
|
+
# yields CMD="" and the guard exits 0 even under FH_PIPE_VERDICT_BLOCK=1 — block mode fails
|
|
47
|
+
# open on a dead interpreter. Accepted, not fixed: the Bash-call surface is re-runnable
|
|
48
|
+
# (reversible → degrade-to-advisory per the Surface-Class Degrade Invariant), and the
|
|
49
|
+
# alternative — exit 2 whenever python3 is missing — would block EVERY Bash call on such a
|
|
50
|
+
# machine, the exact false-block storm the advisory design exists to avoid.
|
|
51
|
+
#
|
|
32
52
|
# Usage:
|
|
33
53
|
# hook: PreToolUse matcher "Bash" → bash scripts/pipe_verdict_guard.sh
|
|
34
54
|
# test: printf '%s' "<command>" | bash scripts/pipe_verdict_guard.sh --stdin-raw
|
|
@@ -88,6 +108,32 @@ fi
|
|
|
88
108
|
|
|
89
109
|
[ -n "$hits" ] || exit 0
|
|
90
110
|
|
|
111
|
+
if [ "${FH_PIPE_VERDICT_BLOCK:-0}" = "1" ]; then
|
|
112
|
+
# Block mode: exit 2 = stderr fed to the model as the blocking reason; stdout ignored by contract.
|
|
113
|
+
printf '%s' "$hits" >&2
|
|
114
|
+
exit 2
|
|
115
|
+
fi
|
|
116
|
+
|
|
117
|
+
# Advisory mode: JSON on stdout, exit 0. additionalContext → model, systemMessage → user.
|
|
118
|
+
# NO permissionDecision — see DELIVERY CHANNEL header. python3 owns the JSON escaping; if it
|
|
119
|
+
# fails, degrade to the old stderr emission (delivery lost, but the call is never disturbed).
|
|
120
|
+
# Capture-then-emit, not stream: a producer that prints partial output and dies must never leave
|
|
121
|
+
# half a JSON object on the hook's stdout (cross-family finding, 2026-07-31). The codec pin must
|
|
122
|
+
# be PYTHONIOENCODING itself — the hits text carries non-ASCII (⚠️), an inherited
|
|
123
|
+
# PYTHONIOENCODING=ascii was measured to kill the emission (silently restoring the exact delivery
|
|
124
|
+
# loss this rewrite closes), and PYTHONUTF8=1 does NOT win over an explicit PYTHONIOENCODING
|
|
125
|
+
# (measured by lane C4: the UTF8-mode pin still emitted 0 bytes under the ascii env).
|
|
126
|
+
json_out=$(printf '%s' "$hits" | PYTHONIOENCODING=utf-8 python3 -c '
|
|
127
|
+
import json, sys
|
|
128
|
+
h = sys.stdin.read()
|
|
129
|
+
print(json.dumps({
|
|
130
|
+
"systemMessage": h,
|
|
131
|
+
"hookSpecificOutput": {"hookEventName": "PreToolUse", "additionalContext": h},
|
|
132
|
+
}))
|
|
133
|
+
' 2>/dev/null)
|
|
134
|
+
if [ -n "$json_out" ]; then
|
|
135
|
+
printf '%s\n' "$json_out"
|
|
136
|
+
exit 0
|
|
137
|
+
fi
|
|
91
138
|
printf '%s' "$hits" >&2
|
|
92
|
-
if [ "${FH_PIPE_VERDICT_BLOCK:-0}" = "1" ]; then exit 2; fi
|
|
93
139
|
exit 0
|
|
@@ -88,6 +88,73 @@ expect "B braced form still caught" HIT 'a | b; rc=${PIPESTATUS[0]}'
|
|
|
88
88
|
echo "-- opt-out --"
|
|
89
89
|
expect "noqa suppresses" CLEAN 'bash g.sh | tail; rc=$? # noqa: pipe-verdict'
|
|
90
90
|
|
|
91
|
+
echo "-- C: delivery channel (closes N=8 — detection without delivery is decoration) --"
|
|
92
|
+
# These lanes assert the CHANNEL, not the detection: per the hook contract, on exit 0 only stdout
|
|
93
|
+
# JSON reaches anyone (additionalContext → model, systemMessage → user); stderr is discarded.
|
|
94
|
+
# A lane that only greps merged output would stay green while the warning goes nowhere — which is
|
|
95
|
+
# exactly the hole the 2026-07-31 rewrite closed. Verdicts are exit codes, not free-form stdout.
|
|
96
|
+
# NAMED RESIDUAL (cross-family LOW, accepted): $(…) capture strips NUL bytes, so a mutant emitting
|
|
97
|
+
# NUL+JSON would pass C1. The producer's hits text is static ASCII+⚠️ with no NUL source, so the
|
|
98
|
+
# lane does not pay for a byte-exact harness; revisit only if the producer ever emits dynamic bytes.
|
|
99
|
+
HIT_CMD='bash x.sh | tail -5; echo "exit=${PIPESTATUS[0]}"'
|
|
100
|
+
payload() { python3 -c 'import json,sys; print(json.dumps({"tool_name":"Bash","tool_input":{"command":sys.argv[1]}}))' "$1"; }
|
|
101
|
+
|
|
102
|
+
# All C lanes measure ONE invocation: stdout, stderr, and exit code from the same run (a pair of
|
|
103
|
+
# runs can each satisfy half the contract while no single run satisfies it — cross-family finding).
|
|
104
|
+
c_errf=$(mktemp)
|
|
105
|
+
|
|
106
|
+
# C1 — advisory hit, full hook payload path: stdout must be one JSON object carrying
|
|
107
|
+
# additionalContext + systemMessage, with permissionDecision ABSENT (emitting "allow" would
|
|
108
|
+
# auto-approve the flagged command — the guard must never grant what it questions). exit 0.
|
|
109
|
+
c_out=$(payload "$HIT_CMD" | bash "$G" 2>"$c_errf"); c_rc=$?
|
|
110
|
+
c_err=$(cat "$c_errf")
|
|
111
|
+
if [ "$c_rc" -eq 0 ] && printf '%s' "$c_out" | python3 -c '
|
|
112
|
+
import json, sys
|
|
113
|
+
d = json.load(sys.stdin)
|
|
114
|
+
h = d["hookSpecificOutput"]
|
|
115
|
+
assert h["hookEventName"] == "PreToolUse"
|
|
116
|
+
assert "PIPE-VERDICT" in h["additionalContext"]
|
|
117
|
+
assert "PIPE-VERDICT" in d["systemMessage"]
|
|
118
|
+
assert "permissionDecision" not in h and "permissionDecision" not in d
|
|
119
|
+
' 2>/dev/null; then
|
|
120
|
+
printf ' ✅ %-52s %s\n' "C1 advisory: stdout JSON, no permissionDecision" OK; pass=$((pass+1))
|
|
121
|
+
else
|
|
122
|
+
printf ' ❌ %-52s rc=%s out=%s err=%s\n' "C1 advisory: stdout JSON, no permissionDecision" "$c_rc" "$c_out" "$c_err"; fail=$((fail+1))
|
|
123
|
+
fi
|
|
124
|
+
|
|
125
|
+
# C2 — block mode: exit 2, warning on stderr (stdout JSON is ignored by contract on exit 2).
|
|
126
|
+
c_out=$(payload "$HIT_CMD" | FH_PIPE_VERDICT_BLOCK=1 bash "$G" 2>"$c_errf"); c_rc=$?
|
|
127
|
+
c_err=$(cat "$c_errf")
|
|
128
|
+
if [ "$c_rc" -eq 2 ] && printf '%s' "$c_err" | grep -q 'PIPE-VERDICT' && [ -z "$c_out" ]; then
|
|
129
|
+
printf ' ✅ %-52s %s\n' "C2 block: exit 2, stderr carries the reason" OK; pass=$((pass+1))
|
|
130
|
+
else
|
|
131
|
+
printf ' ❌ %-52s rc=%s out=%s err=%s\n' "C2 block: exit 2, stderr carries the reason" "$c_rc" "$c_out" "$c_err"; fail=$((fail+1))
|
|
132
|
+
fi
|
|
133
|
+
|
|
134
|
+
# C3 — clean command through the full payload path: NO JSON at all (an empty advisory would still
|
|
135
|
+
# inject an empty reminder every Bash call — silence must stay silent). exit 0.
|
|
136
|
+
c_out=$(payload 'echo hello' | bash "$G" 2>"$c_errf"); c_rc=$?
|
|
137
|
+
rm -f "$c_errf"
|
|
138
|
+
if [ "$c_rc" -eq 0 ] && [ -z "$c_out" ]; then
|
|
139
|
+
printf ' ✅ %-52s %s\n' "C3 clean: no emission at all" OK; pass=$((pass+1))
|
|
140
|
+
else
|
|
141
|
+
printf ' ❌ %-52s rc=%s out=%s\n' "C3 clean: no emission at all" "$c_rc" "$c_out"; fail=$((fail+1))
|
|
142
|
+
fi
|
|
143
|
+
|
|
144
|
+
# C4 — hostile inherited codec: the hits text is non-ASCII (⚠️), and an environment-inherited
|
|
145
|
+
# PYTHONIOENCODING=ascii was measured (2026-07-31) to abort json.dumps and silently restore
|
|
146
|
+
# the pre-fix delivery loss. The guard pins PYTHONUTF8=1; this lane keeps that pin honest.
|
|
147
|
+
c_out=$(payload "$HIT_CMD" | PYTHONIOENCODING=ascii bash "$G" 2>/dev/null); c_rc=$?
|
|
148
|
+
if [ "$c_rc" -eq 0 ] && printf '%s' "$c_out" | python3 -c '
|
|
149
|
+
import json, sys
|
|
150
|
+
d = json.load(sys.stdin)
|
|
151
|
+
assert "PIPE-VERDICT" in d["hookSpecificOutput"]["additionalContext"]
|
|
152
|
+
' 2>/dev/null; then
|
|
153
|
+
printf ' ✅ %-52s %s\n' "C4 ascii-codec env: JSON still delivered" OK; pass=$((pass+1))
|
|
154
|
+
else
|
|
155
|
+
printf ' ❌ %-52s rc=%s out=%s\n' "C4 ascii-codec env: JSON still delivered" "$c_rc" "$c_out"; fail=$((fail+1))
|
|
156
|
+
fi
|
|
157
|
+
|
|
91
158
|
echo
|
|
92
159
|
if [ "$fail" -eq 0 ]; then
|
|
93
160
|
echo "[pipe-verdict-guard] ✅ all $pass known pairs hold"; exit 0
|