@chrono-meta/fh-gate 1.4.71 → 1.4.73

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.
Files changed (38) hide show
  1. package/.claude/rules/.public-surface-patterns.defaults +44 -0
  2. package/.claude/rules/fh_4axis_gate.md +207 -0
  3. package/.claude-plugin/marketplace.json +2 -2
  4. package/AGENTS.md +26 -2
  5. package/CATALOG.md +59 -0
  6. package/README.ja.md +1 -1
  7. package/README.ko.md +1 -1
  8. package/README.md +1 -1
  9. package/README.zh.md +1 -1
  10. package/knowledge/shared/harness-core/measurement-integrity-checklist.md +10 -0
  11. package/knowledge/shared/learnings/subagent_invocations_log.yaml +554 -0
  12. package/package.json +21 -1
  13. package/plugins/fh-commons/.claude-plugin/plugin.json +1 -1
  14. package/plugins/fh-meta/.claude-plugin/plugin.json +2 -2
  15. package/plugins/fh-meta/skills/context-doctor/SKILL.md +42 -4
  16. package/plugins/fh-meta/skills/context-doctor/SKILL_detail.md +38 -0
  17. package/plugins/fh-meta/skills/salience-splitter/SKILL.md +1 -1
  18. package/scripts/chamber_candidate_collect.sh +223 -0
  19. package/scripts/degrade_direction_scan.sh +222 -0
  20. package/scripts/fh-gate.sh +76 -2
  21. package/scripts/fh_session_load.sh +202 -0
  22. package/scripts/gate_pathspec_check.sh +166 -0
  23. package/scripts/prepush_guard_check.sh +374 -0
  24. package/scripts/psa_scan_lib.sh +153 -0
  25. package/scripts/public_surface_scan_files.sh +157 -0
  26. package/scripts/selfcheck.sh +16 -0
  27. package/scripts/session_close_check.sh +171 -0
  28. package/scripts/test_degrade_scan_shell_probes.sh +185 -0
  29. package/scripts/test_fh_gate_regressions.sh +46 -2
  30. package/scripts/test_prepush_stdin_integrity.sh +119 -0
  31. package/scripts/universal_guard_check.sh +280 -0
  32. package/templates/.claude/rules/mcp_tool_gating.md +157 -0
  33. package/templates/.git-hooks/pre-commit +848 -0
  34. package/templates/.git-hooks/pre-push +585 -0
  35. package/templates/PRE-PUBLISH-CHECKLIST.md +85 -0
  36. package/templates/degrade_direction_scan.sh +222 -0
  37. package/templates/predelete_check.sh +72 -0
  38. package/templates/regression_guard.sh +563 -0
@@ -0,0 +1,44 @@
1
+ # public-surface-audit DEFAULTS (COMMITTED — universal, non-operator-private patterns only).
2
+ # The gate loads this + the gitignored .public-surface-patterns (operator literals) so it is
3
+ # NEVER fully blind, even on a fresh clone before the operator populates the gitignored override.
4
+ # Put ONLY patterns that are safe to publish here (no real username/company/companion-store names).
5
+ # NOTE: a pattern here must NOT match its own regex text, or committing this file self-blocks. The
6
+ # /Users/ class below is safe — the literal '[' after /Users/ cannot match the class [a-z0-9_-].
7
+ # Format: severity<TAB>regex
8
+ MED /Users/[a-z0-9_-]+/
9
+ # Tailscale CGNAT (2nd octet 64-127) — operator node / private network topology (a Tailscale-served sidecar box)
10
+ MED 100\.(6[4-9]|[7-9][0-9]|1[01][0-9]|12[0-7])\.[0-9]{1,3}\.[0-9]{1,3}
11
+ #
12
+ # ── Credential SHAPES (added 2026-07-26) ─────────────────────────────────────
13
+ # Until now this file carried only OPERATOR-PRIVATE tokens (home paths, node IPs), so the gate
14
+ # saw an identity leak but was blind to a live CREDENTIAL: a staged AWS key / GitHub PAT /
15
+ # Anthropic key scanned clean (measured known-pair, 2026-07-26 — Case D). These patterns match
16
+ # SHAPES, never values, so they are safe to publish here. Imported from the cross-audited sister
17
+ # asset PromptPartner/agentsmith (`scripts/secret-scan.sh`) — see
18
+ # tracks/_audit/session_2026_07_26_agentsmith-sister.md.
19
+ # Self-match safe: every pattern's own literal text has a '[' where the pattern needs a class
20
+ # member, so none matches itself (verified mechanically before commit).
21
+ # Live-calibrated over the whole tracked tree before shipping: exactly ONE false positive, the AWS
22
+ # documentation key AKIAIOSFODNN7EXAMPLE, closed via the PSA_PLACEHOLDER exemption (both copies).
23
+ # NAMED RESIDUAL — deliberately NOT imported: agentsmith's generic assigned-literal pattern
24
+ # (password|token|api_key)=«8+ chars». In a docs-heavy repo it fires on every documented
25
+ # `export GH_TOKEN=…` placeholder; over-blocking trains PUBLIC_SURFACE_OK into muscle memory and
26
+ # disarms the gate. Un-imported on purpose, not overlooked.
27
+ #
28
+ # MODERN VARIANTS (added in the same session, after a cross-family audit showed the imported set
29
+ # only covered LEGACY token formats): agentsmith's list predates GitHub's fine-grained PATs
30
+ # (`github_pat_`), Slack app-level tokens (`xapp-`), and OpenAI's project/service-account keys
31
+ # (`sk-proj-` / `sk-svcacct-`). All three scanned CLEAN against the first import — verified by
32
+ # staging each shape and watching the gate pass. The alnum-only `sk-…` class cannot consume a
33
+ # hyphenated prefix, which is why `sk-proj-…` needs its own row rather than a widened class.
34
+ HIGH BEGIN [A-Z ]*PRIVATE KEY
35
+ HIGH AKIA[0-9A-Z]{16}
36
+ HIGH ASIA[0-9A-Z]{16}
37
+ HIGH gh[pousr]_[A-Za-z0-9]{20,}
38
+ HIGH github_pat_[A-Za-z0-9_]{30,}
39
+ HIGH xox[baprs]-[A-Za-z0-9-]{10,}
40
+ HIGH xapp-[0-9]-[A-Za-z0-9-]{10,}
41
+ HIGH sk-[A-Za-z0-9]{20,}
42
+ HIGH sk-(proj|svcacct|admin)-[A-Za-z0-9_-]{20,}
43
+ HIGH sk-ant-[A-Za-z0-9_-]{20,}
44
+ HIGH AIza[0-9A-Za-z_-]{35}
@@ -0,0 +1,207 @@
1
+ ---
2
+ paths:
3
+ - "plugins/**/SKILL.md"
4
+ - "knowledge/**/*.md"
5
+ - "templates/**"
6
+ - "AGENTS.md"
7
+ - ".claude/rules/**"
8
+ - ".claude/agents/**/*.md"
9
+ ---
10
+
11
+ <!-- ⚠️ CLAUDE.md 를 glob 에서 **의도적으로 제외**했다 (2026-07-20, cross-family 지적).
12
+ 루트 CLAUDE.md 는 세션 시작에 무조건 읽히므로, glob 에 넣으면 이 규칙이 매 세션
13
+ 즉시 로드된다 = 절감 0 이고 총량은 오히려 늘어난다(67.6k + 12.5k > 76.7k).
14
+ 즉 "상주 파일을 조건부 규칙의 트리거로 넣는 것"은 pointer-illusion 의 부활 경로다.
15
+ CLAUDE.md 편집은 pre-commit 훅이 계속 커버한다. docs/** · plugins/**/*.md(전체) ·
16
+ scripts/** 도 과매칭(읽기만 해도 로드)이라 좁혔다. -->
17
+
18
+ <!--
19
+ FH 4-Axis Auto-Gate — 경로 스코핑된 규칙 (2026-07-20 이전)
20
+
21
+ 왜 여기 있나: CLAUDE.md **파일** 76,706자 중 이 섹션이 10,331자(13.5%)로 단일 최대였다.
22
+ 요약으로 대체했다. 파일 전체는 같은 세션의 다른 정리(중복 3건·New-Skill 게이트 편입)까지 합쳐
23
+ 76,706 → 67,611 (순감 9,095자, 11.9%) — **합산치이지 이 절 하나의 성과가 아니다**.
24
+ 전부 **파일 char 실측**이지 `/context` 상주
25
+ 실측이 아니다(상주는 톱레벨 새 세션 `/context` 로만 잰다 — 이번엔 미측정).
26
+ 이 게이트는 **FH 자산 파일을 건드릴 때만** 필요하므로 `paths:` 로 조건부 로드한다.
27
+ (`paths:` 없는 rules 파일은 세션 시작 시 항상 로드된다 — 반드시 유지할 것.)
28
+ ⚠️ 공식 트리거는 **read** 다("Path-scoped rules trigger when Claude reads files matching
29
+ the pattern" — code.claude.com/docs/en/memory.md). 즉 매칭 파일을 안 읽고 Write 로 신규
30
+ 생성하는 경로엔 이 규칙이 안 실린다. 그 구멍의 floor 는 pre-commit 훅이다.
31
+
32
+ 왜 이 섹션이 이동 후보 1순위였나 — 2축 판정:
33
+ ① 트리거가 **파일**이다 (FH 자산 수정). 의도·발화 트리거가 아니다.
34
+ ② **기계 백스톱이 있다** — `templates/.git-hooks/pre-commit` 이 커밋을 하드 차단한다.
35
+ 즉 이 산문이 안 떠도 훅이 막는다. 산문은 훅 위의 살리언스 층이다.
36
+
37
+ ⚠️ 같은 이유로 **옮기면 안 되는 것들**: Pre-Publish Gate · Destructive-Op Gate ·
38
+ Irreversibility 공통 척추. 그것들은 **파일이 아니라 의도로 발동한다**
39
+ (`gh repo create --public` 은 파일을 건드리지 않는다). 경로 스코핑하면
40
+ 정확히 그 경로에서 안 뜬다 = fail-open.
41
+
42
+ 과거 실패 참조: FH 가 detail 포인터 뒤로 ~50k 를 옮겼으나 대상이 여전히 auto-load 라
43
+ 절감이 0 이었다(pointer-illusion). `paths:` 는 플랫폼 레벨 강제라 그 함정이 없다.
44
+ -->
45
+
46
+ ## FH Improvement 4-Axis Auto-Gate (Self-Verification Orchestrator)
47
+
48
+ **Whenever the AI modifies FH assets** (SKILL.md · **`SKILL_detail.md`** · `.claude/rules/*.md` · `knowledge/shared/rules/*.md` (relocated protocol rules — always full-gate, NOT under the knowledge carve-out) · `templates/` · `CLAUDE.md` · substantive `knowledge/` docs · substantive `docs/*.md` · `AGENTS.md` — see Substantive carve-out below),
49
+ the 4-axis verification chain runs **automatically before the first commit** of that session.
50
+ No user request is needed — this is a mandatory autonomous step, not a proposal.
51
+
52
+ > **`SKILL_detail.md` added 2026-07-26.** It was absent from this list *and* from both gate
53
+ > implementations because the matching term was the literal `SKILL\.md`, which the string
54
+ > `SKILL_detail.md` does not contain (the underscore breaks it). Measured at the time: 17 files /
55
+ > 208,710 B = **27.7% of the skill-spec surface**, 16 of 17 carrying fenced code blocks — i.e. real
56
+ > executable content, precisely what the Substantive carve-out below says must be gated *wherever it
57
+ > lives*. It leaked twice for real (`371c04f`, `e661931` — both single-file edits to
58
+ > `phantom-quench/SKILL_detail.md`, a gate skill's own behavioral spec, with zero 4-axis coverage).
59
+ > **The structural lesson outlives the fix**: `salience-splitter` *widens* a hole of this shape every
60
+ > time it relocates content to lean the resident layer, so **every split must re-ask whether the
61
+ > destination path is inside the gate** — coverage otherwise shrinks as the diet succeeds.
62
+ > Mechanical anchor: `scripts/gate_pathspec_check.sh` (known-pair, wired into pre-commit).
63
+
64
+ **Commit gate**: `git commit` on FH asset changes is hard-blocked by `templates/.git-hooks/pre-commit` until all required axes PASS. Hook installation (one-time): `git config core.hooksPath templates/.git-hooks && chmod +x templates/.git-hooks/pre-commit templates/.git-hooks/pre-push` (the same `core.hooksPath` also activates the **pre-push** Destructive-Op gate — see that section below).
65
+
66
+ ```
67
+ FH asset modified → Axis 1 (templates/regression_guard.sh --pr {BRANCH})
68
+ → Axis 2 (/steel-quench) → Axis 3 (/phantom-quench)
69
+ → marker: tracks/_meta/.axes_23_passed_{branch}_{date}.marker
70
+ (required fields: axis2-engine / axis2-model / floor-status / axis2-evidence;
71
+ hook validates mechanically: below-floor blocks without below-floor-ack, and axis2-evidence
72
+ must be non-vacuous — a recorded verdict/count, not "it ran". Marker scope is form +
73
+ non-vacuity + auditability, NOT provenance — a fabricated marker is the weekly-audit + operator
74
+ residual by design, do NOT fake-close it.
75
+ → **Detail**: See `knowledge/shared/harness-core/claude_md_gate_details.md §Marker-Irreducibility`
76
+ — why the below-floor-ack is structurally irreducible for an autonomous runner + the
77
+ operator-present GPG hard-close option — read when auditing or attempting to harden the marker.)
78
+ → Axis 4 (/edit-manifest RECORD, today's entry in edit_manifest.yaml)
79
+ → All 4 PASS → git commit allowed | Any FAIL → fix inline, re-run
80
+ ```
81
+
82
+ **Why automatic**: Each axis catches a different defect class; asking separately means slip-through. **Why hook**: CLAUDE.md rules are advisory — the hook physically blocks commit until marker + manifest exist. **Scope**: active from the moment any FH file is modified in the session.
83
+
84
+ **Lightweight exception** (Axis 1 + 4 only, skip Axes 2–3): Sessions where **zero SKILL.md / rules / templates files changed** (e.g., CATALOG.md entry, tracks/ update). The hook detects this automatically — no Axes 2+3 marker required for light-only commits. Judgment is file-based, not subjective.
85
+
86
+ **Substantive carve-out — `knowledge/` · `docs/*.md` · `AGENTS.md`** (Axes 2–3 DO run, despite these not being SKILL/rules/templates): a change to any of these is **not** light if its diff adds a fenced code block (```` ``` ````) or a citation/version claim (`arXiv:` / `DOI` / `http` / a versioned dependency like `x.y.z`). Executable patterns and factual claims need phantom-detection + adversarial review *wherever they live* — `knowledge/` Implementation-Patterns sections carry runnable commands, `docs/` holds published guides, and `AGENTS.md` is the Codex-user entry point, so a phantom skill name or wrong version there is an external-facing error the gate must catch. Prose-only edits (typos, rewording, link fixes) stay light. Detection is mechanical: `git diff` adds a ```` ``` ```` fence or a citation token → run Axes 2–3.
87
+
88
+ **Unavailable axis**: If steel-quench or phantom-quench are not installed, note `Axis N: skipped (skill unavailable)` and proceed. Axis 1 PASS alone is sufficient to unblock a PR when Axes 2–3 are unavailable. Axis 4 (edit-manifest): if the skill is not installed, substitute a manual one-line prediction appended to `tracks/_meta/edit_manifest.yaml` — the record is what matters, not the skill.
89
+
90
+ **Target-tier sim gate (Mode D supplement — all change classes: fix, improvement, new asset)**: the
91
+ discriminator is not the change class but the **enforcement column**: does the asset's effect depend on
92
+ a session *following prose instructions* (salience-dependent — rules, onboarding scaffolds, SKILL.md
93
+ trigger behavior), or is it mechanically enforced (hooks, scripts — tier-independent, normal 4-axis
94
+ path, exempt)? For salience-dependent changes, verify with a **blind simulation in an isolated Agent**
95
+ (no main-session reasoning inherited — isolation is the FH mechanism that keeps the sim honest) with
96
+ `model:` pinned to the tier the change must survive on — **default sim tier = Sonnet** (the base
97
+ floor every FH behavior must survive on, `sonnet_floor_doctrine.md`). Application strength scales
98
+ with context:
99
+ - **Mode D (FH self-dev) — near-mandatory**: any salience-dependent FH asset change runs the sim
100
+ before Done, at Sonnet by default. Mandatory without exception when the change fixes a behavioral
101
+ miss *observed* on a specific tier — sim at that same tier, even below Sonnet (the verification
102
+ tier must match the failure tier; fixing on a stronger model and verifying by review alone leaves
103
+ "does it fire on the weaker tier?" unanswered).
104
+ - **Field harness assets (templates/ propagated via Full-Harness Mode) — conditional**: sim at the
105
+ default field tier (Sonnet) when the behavior is load-bearing (gates, onboarding, destructive/publish
106
+ paths); skip with a one-line note for low-stakes prose.
107
+ - **Light mapping (tracks/ registration, CATALOG entries) — exempt**, alongside mechanical changes
108
+ (hook logic, scripts, file moves — tier-independent by construction).
109
+
110
+ **Autonomy floor**: the skip/run *judgment* on conditional cases is itself depth-sensitive — trust it
111
+ only at opus-tier or above. A below-floor orchestrator does not silently skip — and does not stall:
112
+ its default is to RUN the sim (the conservative branch needs no trust); it asks the operator only when
113
+ no runnable path exists (run-first, ask-last — sonnet_floor_doctrine.md §Autonomy at Sonnet).
114
+
115
+ Record sim results in the Axes 2–3 marker + sub-agent invocation log.
116
+
117
+ > **Detail**: See `knowledge/shared/harness-core/claude_md_gate_details.md §Sim-Dispatch-Fallback` — the
118
+ > headless `claude -p --model` fallback when in-session model-pin is unavailable, the saturation-disguise
119
+ > retry (compact-then-retry once), and the credit-pool caveat — read when a model-pinned dispatch fails.
120
+
121
+ **Measurement-integrity pre-flight**: when the sim/dispatch is a *cross-model measurement* (pinned to a
122
+ tier, comparing model behaviors, or feeding a published claim), **the instrument must be verified before
123
+ the measurement is trusted**.
124
+
125
+ > **Detail**: See `knowledge/shared/harness-core/measurement-integrity-checklist.md` — pin the display
126
+ > name not a slug (silent fallback to a weaker model is a measured failure) · reps ≥ 3 on any
127
+ > borderline/contested verdict (single draw = noise) · use a discriminating identity probe (a generic
128
+ > "OK" proves nothing about which model answered) — read **before** running any cross-model measurement.
129
+
130
+ **Floor-tier canary (optional pre-screen — token-free, *below* the Sonnet sim)**: a local model ≤ Sonnet
131
+ can blind-pre-screen a salience-dependent edit before the Sonnet dispatch is spent. **Canary, NOT gate**:
132
+ a PASS adds cheap floor confidence and you still run the Sonnet sim; a FAIL never blocks alone. The
133
+ terminal verdict stays with the **Sonnet-or-higher governor bound to a mechanical anchor** — **no
134
+ judge-only path**, no weak-local-judge regression of the judge-robustness principle.
135
+
136
+ > **Detail**: See `knowledge/shared/harness-core/claude_md_gate_details.md §Floor-Tier-Canary` — the local
137
+ > model/panel options, the blind-probe procedure, dogfood evidence, and the FAIL-triage (real salience gap
138
+ > vs floor-model quirk) — read when running a floor canary.
139
+
140
+ **Axis ownership** (each skill is already complete — orchestrator only coordinates):
141
+
142
+ | Axis | Skill | What it catches |
143
+ |---|---|---|
144
+ | Backward | `templates/regression_guard.sh` | Critical section loss, broken refs, syntax errors, line reduction |
145
+ | Adversarial | `steel-quench` | Trigger phrase collisions, design attack surface, over-engineered steps |
146
+ | Forward | `phantom-quench` | Phantom references, paths that don't exist, stale external links |
147
+ | Record | `edit-manifest` RECORD | Logs predicted impact — closes the predict-verify loop for future harvest-loop |
148
+
149
+ **Cross-family complement (Axis 2, autonomous when consented)**: `steel-quench` dispatches in-session at the
150
+ session tier — **same family** as the governor, so it shares the governor's blind spots. For a **load-bearing**
151
+ change (gates · irreversible-surface code · doctrine), `auto-decorrelation` is the standing cross-family
152
+ verifier: it recruits ≥1 **different-family** auditor when the sidecar panel is discoverable, and degrades
153
+ honestly to single-session when none is. **Autonomous once the operator has consented** (one-time, in the
154
+ UAP — `[[user_adaptation_profile]]`); the governor keeps the terminal verdict and **source-grounds** every
155
+ sidecar finding before acting on it (`[[feedback_judge_robustness_mechanical_anchor]]`).
156
+
157
+ > **Detail**: See `knowledge/shared/harness-core/claude_md_gate_details.md §Cross-Family-Complement` — the
158
+ > UAP sidecar mapping (which family for which task class) and the 2026-06-27 dogfood evidence — read when
159
+ > recruiting or configuring a cross-family auditor.
160
+
161
+ ### Mode D Model Notice (fires once, at the same trigger as this gate)
162
+
163
+ When FH self-dev begins (an FH asset is about to change), check the **session model** and surface **one
164
+ line**, then proceed — never block, **never switch the model** (human override inviolable): opus-tier+ →
165
+ no notice · below-opus → **dispatch-first recommend** (keep Sonnet + route depth turns to sidecar/opus
166
+ dispatch; `/model opus` pin = secondary — `sonnet_floor_doctrine.md`) · unknown → static fallback recommend. Once per session;
167
+ field-project (non-FH-asset) sessions never see it. Whether a session actually *escalates* (not just this
168
+ advisory) is governed separately by `capability_escalation_consent.md`.
169
+
170
+ > **Detail**: See `knowledge/shared/harness-core/claude_md_gate_details.md §Mode-D-Model-Notice` — the
171
+ > exact 3-branch wording (한글), the full guards, and the capability-escalation-consent cross-ref — read
172
+ > when surfacing the notice.
173
+
174
+ ---
175
+
176
+ <!-- Relocated from always-loaded CLAUDE.md 2026-07-20 (Fable residency judgment, rank 2).
177
+ ①파일 트리거(신규/편집 SKILL.md) ②기계 백스톱 검증됨 — pre-commit:105 가 어떤 SKILL.md
178
+ 경로에도 4축 전체를 발동하고, :552-558 에 신규스킬 count-consistency 슬라이스가 따로 있다.
179
+ glob 은 신설이 아니라 이 파일 frontmatter 의 기존 plugins/**/SKILL.md 를 재사용한다.
180
+ 잔여: paths: 는 read 트리거라 '스킬을 맨바닥에서 Write 로 만드는' 경로엔 안 실린다 —
181
+ 오늘 아침 4축 분리가 수용한 것과 동일한 잔여이고 floor 도 동일(pre-commit). -->
182
+
183
+ ## New Skill Creation Pre-Commit Gate
184
+
185
+ All 6 items below must pass before committing a new SKILL.md. If any fails, fix and re-commit.
186
+
187
+ | Item | Criterion |
188
+ |---|---|
189
+ | **Role duplication check** | Pass `/asset-placement-gate` — no overlap with existing role clusters, **platform built-ins (Tier 0), or `claude-plugins-official` (Tier 1 official)**. Reinventing an official capability requires explicit justification in the SKILL.md (no-reinvention rule — FH builds only what adds governance) |
190
+ | **Description diet** | Plain text / 0 self-marketing expressions / 0 emphasis words (⭐, "critical", "groundbreaking") |
191
+ | **Done When defined** | At least 1 explicit completion condition |
192
+ | **Check-class declared** | Each Done When condition states its check class — mandatory-pass / measured / judged (`harness_6axis_framework.md` §Axis 5). Any judged condition names its adversarial pairing — no judge-only path |
193
+ | **Natural language triggers** | At least 3 examples that work without internal vocabulary. This is a **form** check (judged — do the examples avoid internal jargon). For a load-bearing gate/router skill it can be upgraded **judged → measured** with steel-quench's `Step 0.5 — Trigger-Accuracy Probe` (a dispatched should-fire / near-miss-should-not-fire fire-count), turning "do these triggers collide?" from a guess into a number. Optional for ordinary skills; recommended when the skill is a routing/gate surface |
194
+ | **Independently executable** | Confirmed to work without other FH skills (or dependencies are explicitly documented) |
195
+
196
+ Skills without a Done When definition automatically qualify as harness-doctor L2 M-tier.
197
+ Check-class declaration applies to **new** skills; existing skills backfill opportunistically
198
+ (when next edited), not retroactively. **Obligation (always-loaded):** a **routing/gate skill** (primary
199
+ output = a dispatch decision or pass/block verdict) owes a **one-time `Step 0.5` baseline trigger-probe**
200
+ at the next `harness-doctor` run **and a re-probe whenever its trigger phrases change** — not optional for
201
+ that skill class, and not a retroactive sweep of all routers.
202
+
203
+ > **Detail**: See `knowledge/shared/harness-core/claude_md_gate_details.md §New-Skill-Backfill` — the
204
+ > probe mechanics (fire-count procedure), the baseline-floor rationale, and the mechanical "routing/gate
205
+ > skill" test — read when editing a router/gate skill.
206
+
207
+ ---
@@ -11,13 +11,13 @@
11
11
  "plugins": [
12
12
  {
13
13
  "name": "fh-meta",
14
- "version": "1.4.71",
14
+ "version": "1.4.73",
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.71",
20
+ "version": "1.4.73",
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/AGENTS.md CHANGED
@@ -104,11 +104,11 @@ For complex multi-step tasks, run `/agent-composer` first to plan which agents t
104
104
 
105
105
  The methodology layer (`tracks/`, `knowledge/`, `SKILL.md` docs) is Codex-compatible beta. Any AI model can follow skill workflows by reading SKILL.md files directly; the automation layer (hooks, plugin-channel agents under `plugins/*/agents/`, `/model`) is Claude Code-native and requires manual adaptation. FH's own agents are auto-loaded via the plugin channel when the plugin is enabled — `.claude/agents/` is the field-project override slot, not where FH ships its agents. Non-Claude runtimes use this `AGENTS.md`, `plugins/*/agents/*.md`, and `scripts/fh-run.sh` to apply the same methodology via adapter.
106
106
 
107
- ### Non-Claude runtimes: four things CLAUDE.md holds that you will not auto-load
107
+ ### Non-Claude runtimes: five things CLAUDE.md holds that you will not auto-load
108
108
 
109
109
  `.claude/rules/*.md` with `paths:` frontmatter is a **Claude Code platform feature** — those files are
110
110
  auto-loaded into a Claude Code session when it reads a matching file, and **your runtime has no equivalent**.
111
- So four things that govern behavior are not going to reach you on their own. Read them explicitly:
111
+ So five things that govern behavior are not going to reach you on their own. Read them explicitly:
112
112
 
113
113
  1. **FH asset changes run a mandatory 4-axis verification chain before the session's first commit.**
114
114
  Detail (axis definitions · marker required fields · lightweight exception · substantive carve-out):
@@ -167,6 +167,30 @@ So four things that govern behavior are not going to reach you on their own. Rea
167
167
  > the gate-routing table, the Sonnet-floor boundaries, and the origin defect — **open it directly**
168
168
  > before applying the ladder or when a gap appears.
169
169
 
170
+ 5. **A scan, checker, or metric in this repo is not evidence until it has been shown to work on the
171
+ target you are pointing it at.** This one is easy to skip because the tooling looks finished, so it
172
+ is worth two cheap steps before you rely on a number it produces:
173
+
174
+ - **Run it against one case you already know the answer to, and one you know is clean.** A tool that
175
+ cannot separate those two has not been shown to measure anything, so its output cannot ground a
176
+ claim about the target — it may still be right, you just have no way to tell. This
177
+ repo has produced that exact result more than once — an ASCII-token scanner run over a Korean
178
+ corpus scored ~96% false positives, and a shell-shape scanner reported a fail-open script as
179
+ "clean" because every one of its probes was written for Python syntax.
180
+ - **Open one hit by hand before you state a count anywhere** — including in chat, not only in a file.
181
+ An unverified figure is anchored the moment it is said, and then has to be corrected everywhere it
182
+ travelled.
183
+
184
+ Two conventions that follow from this, and that the rest of the repo assumes you are using:
185
+ *an empty result is not a zero* — a scan that found no target files, or died mid-run, reports
186
+ `UNMEASURED`, never `0` — and *an extreme result (everything passed, everything failed) is a reason
187
+ to suspect the instrument before the target.*
188
+
189
+ Nothing enforces this mechanically; the trigger is your own intent to trust an output, which no hook
190
+ can see. Detail, including the known-pair procedure and the failure catalogue:
191
+ `knowledge/shared/harness-core/measurement-integrity-checklist.md` — **open it directly** before
192
+ running a scan whose count you will report.
193
+
170
194
  The irreversible-surface gates (Pre-Publish · Destructive-Op) likewise live in CLAUDE.md and fire on
171
195
  **intent**, not on a file — read them before any publish, delete, or history-rewrite. `pre-push` enforces
172
196
  the git-side destructive surface mechanically for every runtime.
package/CATALOG.md CHANGED
@@ -4,6 +4,65 @@ AI reads this file first when searching past work. Open individual files for det
4
4
 
5
5
  ---
6
6
 
7
+ ## 2026-07-26 — Scan logic single-sourced · FH_BACKEND=cross · v1.4.72
8
+
9
+ - **Single-sourcing** (`scripts/psa_scan_lib.sh`): three near-duplicate implementations of
10
+ public-surface pattern loading/matching (pre-commit, pre-push, publish scanner) collapsed into one.
11
+ Motivation was measured, not aesthetic — across 7 cross-family rounds on the same subsystem, every
12
+ confidentiality defect found was a divergence between the copies (readable/non-empty override check
13
+ in one, no-TAB rejection in two of three, the per-file LOW allowlist in exactly one — which is how
14
+ the push gate blocked its own first real push). Duplication removal verified mechanically:
15
+ `PSA_PLACEHOLDER` 3→1. Deliberately NOT unified, each with an in-file reason: degrade direction per
16
+ surface, the publish scanner's `grep -a` binary handling, and its stricter allowlist.
17
+ - **`FH_BACKEND=cross`**: runs both model families and UNIONs findings (a finding only one family saw
18
+ is still a finding, so union rather than vote); verdict is the most severe leg. The output always
19
+ declares which legs actually ran (`FH_GATE_LEGS` / `FH_GATE_DECORRELATED`) and degrades loudly to a
20
+ single leg when only one family is installed — a single-family result reading as cross-checked is
21
+ the same defect class as a check that did not run reading as PASS. Implemented as a recursive
22
+ wrapper so the npm-shipped single-backend path is untouched.
23
+ - **Over-block correction**, found by this repo's own selfcheck (T7: *"guard over-fires; that trains
24
+ the override"*): the new push-time legs blocked whenever this operator's gitignored override was
25
+ absent. The reasoning did not survive re-examination — that file holds one operator's literals, so
26
+ another environment lacking it was never protected by it. Corrected to warn; what still blocks is a
27
+ genuinely broken pattern source. Applicability is now decided mechanically before any dependency is
28
+ required, and an N/A skip is announced rather than silent.
29
+ - **Anchors**: `universal_guard_check` 22 pairs · `prepush_guard_check` 12 pairs · fh-gate regressions
30
+ 31. Both anchors test the STAGED blob, score a hook runtime fault as its own failure class, and
31
+ require a BLOCK to name a confidentiality cause (after the library landed, 6 of 8 BLOCK pairs were
32
+ green for a harness reason).
33
+ - **Published**: npm `@chrono-meta/fh-gate@1.4.72`, tag `v1.4.72`, registry confirmed by polling.
34
+ - **Residual**: `cross` has no real-model end-to-end run yet (deterministic fakes only); the union does
35
+ not deduplicate across legs (a false duplicate is cheap, a dropped finding is not).
36
+ - Tags: `single-source` `decorrelation` `cross-family` `known-pair` `over-block` `release`
37
+
38
+ ## 2026-07-26 — Confidentiality gate: scope decoupled from the 4-axis classifier (gate-locality N=5)
39
+
40
+ - **Origin**: source-reading a cross-audited sister asset (`PromptPartner/agentsmith`, `leak-gate.sh`).
41
+ Its `SCOPE=()` comment — *"an excluded file is a hole a real leak can sit in"* — asked of this repo
42
+ surfaced a different shape of the same hole: the pre-commit confidentiality scan sat below
43
+ `exit 0 # No FH assets staged`, so its trigger silently inherited the 4-axis asset pathspec. A commit
44
+ staging only non-asset paths skipped it entirely. Known-pair measured, both directions: the identical
45
+ leak line blocks in `CATALOG.md` and passes unseen in `README.md` alone. Surface: 46/241 tracked files
46
+ (19.1%) unscannable that way, 32 of them also outside npm `files[]`.
47
+ - **Repair**: the confidentiality/privacy guards moved into `run_universal_guards()`, invoked before the
48
+ early exit — they guard the publish boundary, not FH asset structure. Credential SHAPES imported from
49
+ the sister asset (the scan previously matched only operator-private identity tokens, so a live AWS/GitHub/
50
+ Anthropic key scanned clean), live-calibrated over the whole tree: one false positive, closed by an
51
+ exact-literal exemption. A push-time content scan was added over the commits a push actually publishes.
52
+ - **Verification**: 7 cross-family adversarial rounds (codex/gpt-5.5). 30 findings; 2 accepted as named
53
+ residuals with the success line narrowed to claim only what it checks, the rest fixed. One author
54
+ refutation withdrawn when the auditor showed `npm publish` is not a backstop for a public git repo.
55
+ Anchors: `scripts/universal_guard_check.sh` (pre-commit) and `scripts/prepush_guard_check.sh` (pre-push),
56
+ both testing the STAGED blob and scoring a hook runtime fault as its own failure class.
57
+ - **Also**: `validate_yaml.sh` was found to be the defect rather than the file it flagged (it grepped for
58
+ `': '` without checking whether the value was quoted, and its `--fix` folded quotes into an already-correct
59
+ string) — rewritten parse-first with an `UNCALIBRATED` degrade. `sync-to-be.sh` returned the status of its
60
+ last loop iteration, so a successful sync reported failure, the Stop-hook cooldown stamp was never written,
61
+ and the companion store went uncommitted for ~3.7h; introduced by the same-day patch that added mirror banners.
62
+ - **Residual**: three near-duplicate scan implementations remain; single-sourcing them is the next PR and the
63
+ real convergence — every leniency divergence found here was a propagation miss between those copies.
64
+ - Tags: `gate-locality` `confidentiality` `cross-family` `known-pair` `sister-asset` `publish-boundary`
65
+
7
66
  ## Sessions
8
67
 
9
68
  <!-- Add entries in reverse date order (newest at top) -->
package/README.ja.md CHANGED
@@ -198,7 +198,7 @@ FH_BACKEND=auto npx --package @chrono-meta/fh-gate fh-gate "src/foo.ts" full
198
198
  # → FH_GATE_VERDICT: PASS | PENDING | BLOCKED | ESCALATE
199
199
  ```
200
200
 
201
- `fh-gate` は両ランタイムに同じ FH ガバナンスプロンプトを使います。`FH_BACKEND=claude` は `claude --print` を、`FH_BACKEND=codex` は `codex exec` を実行し、`FH_BACKEND=auto` は両 CLI が揃っていれば Codex を優先します。
201
+ `fh-gate` は両ランタイムに同じ FH ガバナンスプロンプトを使います。`FH_BACKEND=claude` は `claude --print` を、`FH_BACKEND=codex` は `codex exec` を実行し、`FH_BACKEND=auto` は両 CLI が揃っていれば Codex を優先します — ただし `auto` はフォールバック*選択*であり、レグは 1 つだけ走ります。`FH_BACKEND=cross` は両ファミリーを走らせて findings を union します(一方だけが見つけた指摘も指摘なので、投票ではなく union)。判定はレグ中で最も重いものです。コストは約 2 倍なので既定ではなく、判定・ゲート・不可逆な面の変更に使います。出力は実際に走ったレグを常に明示します(`FH_GATE_LEGS:`、`FH_GATE_DECORRELATED:`) — 片方のファミリーしかない環境では単一レグに縮退し、その事実を明記します。
202
202
 
203
203
  Claude Code の外でスキルやエージェントを直接実行するには `fh-run` を使います:
204
204
 
package/README.ko.md CHANGED
@@ -197,7 +197,7 @@ FH_BACKEND=auto npx --package @chrono-meta/fh-gate fh-gate "src/foo.ts" full
197
197
  # → FH_GATE_VERDICT: PASS | PENDING | BLOCKED | ESCALATE
198
198
  ```
199
199
 
200
- `fh-gate`는 두 런타임에 동일한 FH 거버넌스 프롬프트를 씁니다. `FH_BACKEND=claude`는 `claude --print`를, `FH_BACKEND=codex`는 `codex exec`를 실행하며, `FH_BACKEND=auto`는 두 CLI가 모두 있으면 Codex를 우선합니다.
200
+ `fh-gate`는 두 런타임에 동일한 FH 거버넌스 프롬프트를 씁니다. `FH_BACKEND=claude`는 `claude --print`를, `FH_BACKEND=codex`는 `codex exec`를 실행하며, `FH_BACKEND=auto`는 두 CLI가 모두 있으면 Codex를 우선합니다 — 다만 `auto`는 폴백 *선택*이라 레그를 하나만 돌립니다. `FH_BACKEND=cross`는 두 패밀리를 모두 돌려 findings를 union 합니다(한쪽만 본 지적도 지적이므로 투표가 아니라 union). 판정은 레그 중 가장 무거운 것입니다. 비용이 약 2배라 기본값이 아니며, 판정·게이트·비가역 표면 변경에 씁니다. 출력은 실제로 돈 레그를 항상 밝힙니다(`FH_GATE_LEGS:`, `FH_GATE_DECORRELATED:`) — 한 패밀리만 설치된 머신에서는 단일 레그로 내려가되 그 사실을 명시합니다. 단일 패밀리 결과가 교차검증된 것처럼 읽히는 편이 더 나쁘기 때문입니다.
201
201
 
202
202
  Claude Code 밖에서 스킬이나 에이전트를 직접 실행하려면 `fh-run`을 씁니다:
203
203
 
package/README.md CHANGED
@@ -209,7 +209,7 @@ FH_BACKEND=auto npx --package @chrono-meta/fh-gate fh-gate "src/foo.ts" full
209
209
  # → FH_GATE_VERDICT: PASS | PENDING | BLOCKED | ESCALATE
210
210
  ```
211
211
 
212
- `fh-gate` uses the same FH governance prompt for both runtimes. `FH_BACKEND=claude` runs `claude --print`; `FH_BACKEND=codex` runs `codex exec`; `FH_BACKEND=auto` prefers Codex when both CLIs are present.
212
+ `fh-gate` uses the same FH governance prompt for both runtimes. `FH_BACKEND=claude` runs `claude --print`; `FH_BACKEND=codex` runs `codex exec`; `FH_BACKEND=auto` prefers Codex when both CLIs are present — note that `auto` is fallback *selection*: it runs ONE leg. `FH_BACKEND=cross` runs BOTH families and unions their findings (a finding only one family saw is still a finding, so it unions rather than votes); the verdict is the most severe across legs. It costs ~2x, so it is for load-bearing verdict/gate/irreversible-surface changes, not a default. The output always declares which legs actually ran (`FH_GATE_LEGS:`, `FH_GATE_DECORRELATED:`) — on a machine with only one family, `cross` degrades to that single leg and says so, because a single-family result that reads as cross-checked is worse than an honest one.
213
213
 
214
214
  For direct skill or agent execution outside Claude Code, use `fh-run`:
215
215
 
package/README.zh.md CHANGED
@@ -187,7 +187,7 @@ FH_BACKEND=auto npx --package @chrono-meta/fh-gate fh-gate "src/foo.ts" full
187
187
  # → FH_GATE_VERDICT: PASS | PENDING | BLOCKED | ESCALATE
188
188
  ```
189
189
 
190
- `fh-gate` 对两种运行时使用同一套 FH 治理提示。`FH_BACKEND=claude` 运行 `claude --print`;`FH_BACKEND=codex` 运行 `codex exec`;`FH_BACKEND=auto` 在两个 CLI 都存在时优先选择 Codex
190
+ `fh-gate` 对两种运行时使用同一套 FH 治理提示。`FH_BACKEND=claude` 运行 `claude --print`;`FH_BACKEND=codex` 运行 `codex exec`;`FH_BACKEND=auto` 在两个 CLI 都存在时优先选择 Codex —— 但 `auto` 是回退式*选择*,只运行一条腿。`FH_BACKEND=cross` 会运行两个模型家族并对 findings 取并集(只有一方发现的问题仍然是问题,因此是并集而非投票),判定取各腿中最严重者。成本约为 2 倍,因此并非默认值,适用于判定/门禁/不可逆面的变更。输出始终声明实际运行了哪些腿(`FH_GATE_LEGS:`、`FH_GATE_DECORRELATED:`) —— 在只装了一个家族的机器上,`cross` 会降级为单腿并明确说明,因为让单家族结果读起来像交叉验证过更糟。
191
191
 
192
192
  若要在 Claude Code 之外直接执行技能或 agent,使用 `fh-run`:
193
193
 
@@ -120,6 +120,8 @@ here.** Three shapes, all observed 2026-07-20 in a single session:
120
120
  | n+7 | **Instrument sees only part of its own declared surface** | An "always-loaded footprint" scan summed files rooted at `$TARGET`, silently omitting the auto-loaded memory index living outside it — **61% of the real resident surface** | A known-positive (a file you *know* is resident) fails to appear in the sum |
121
121
  | n+8 | **A cheap proxy substituted for the real property** | Index-line/topic-file **size ratio** used as a proxy for *content coverage*; minimum ratio 3.7× read as "safe" — while an entry whose file was 3.7× larger still lacked every fact the index carried | One known case checked by content, not size, inverts the verdict immediately |
122
122
  | n+9 | **Language / encoding assumption mismatch** | An **ASCII-token scanner run over a Korean corpus**: the index wrote `catch`, `MERGED`, `expert-system`; the files wrote `잡았다`, `머지`, `케이스크래프트` → every token scored as missing. **~96% false positives** | One known-negative (an entry you know is fully covered) scores as "missing" → mismatch exposed |
123
+ | n+10 | **Accepted into the scanned set, but no probe matches that shape** — the instrument counts the file as covered and reports it *clean* | `degrade_direction_scan.sh` collected `.sh` files while every probe was Python-shaped (`except:` / `.get(k, True)` / `if not x:`). A known-positive bash file with four default-toward-PASS constructs scored **0/4**, and the output read `no default-toward-PASS smells in 1 scanned py/sh file` (2026-07-28) | The known-positive of *that shape* scores 0 while the summary says "scanned" — the tell is coverage claimed without detection demonstrated |
124
+ | n+11 | **The collection predicate, not the probe, is what silently drops the target** | Same scan: git hooks are named `pre-push` (no extension) under `.git-hooks` (dotted directory), and the extension test ran against the **full path**, so FH's own mechanical floor reported `no scannable (py/sh) target files`, exit 0 | Point the instrument at a directory you *know* holds a positive; an empty file list is the finding, not a clean result |
123
125
 
124
126
  Secondary false-positive sources in the same run, worth checking explicitly: **whitespace/hyphen
125
127
  variants** (`3주새` vs `3주 새`), and treating a line's **navigational annotation** (`(detail …, archive)`)
@@ -134,6 +136,14 @@ as a factual claim.
134
136
  `UNMEASURED`, never `0`.
135
137
  - An instrument that produces an **impossible value** (all-pass, all-fail, or a self-scan in which the
136
138
  running tool does not detect itself) is suspect **before** its target is. Suspect the instrument first.
139
+ - **"Scanned" is a claim, and it is separate from "covered."** A scanner that admits a file type into its
140
+ scanned set owes a known-positive *of that type*; without one, its clean message is a false clean, which
141
+ is strictly worse than an honest "not covered" (n+10). Same for the collection step: an empty file list
142
+ is a calibration failure to report, never a clean run (n+11).
143
+ - **A probe that flags the prescribed remedy is a defect in the probe.** Measured 2026-07-28: flagging
144
+ `${count:-0}` — the integer sanitization that closes the `pipefail`-fallback class — would push an author
145
+ to delete the fix. Hand-check a sample of hits before shipping a probe; on this corpus 6/6 sampled hits
146
+ were false positives and the scoping that followed cut the load from 73 to 14.
137
147
 
138
148
  ### Done When
139
149