@chrono-meta/fh-gate 1.4.34 → 1.4.35

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.md CHANGED
@@ -227,6 +227,23 @@ post-compaction 2026-06-12). 2026-06-15+: headless `claude -p` draws from the ha
227
227
  subscription — prefer in-session Agent dispatch when the plan gate allows; take the headless fallback
228
228
  knowingly. Record sim results in the Axes 2–3 marker + sub-agent invocation log.
229
229
 
230
+ **Floor-tier canary (optional pre-screen — token-free, *below* the Sonnet sim)**: a local model weaker
231
+ than or comparable to Sonnet (e.g. `ollama run qwen3:8b` on the local host today; a cross-family local
232
+ panel — qwen3.x:27b / gemma4:12b-qat / gpt-oss:20b / devstral — on a GPU host once its remote-exec path
233
+ is live) can pre-screen a salience-dependent edit *before* the Sonnet dispatch is spent: a rule that
234
+ fires correctly on the floor model is *evidence of* robustness below Sonnet (one floor sample, not proof
235
+ — hold the asymmetric-skepticism discipline). Blind probe — feed the verbatim rule text + a scenario,
236
+ demand a strict YES/NO + one-line reason, judge whether the rule fired (mechanism dogfood-verified
237
+ 2026-06-20: a local `qwen3:8b` correctly gated the public install-wizard local-LLM-offload item in both
238
+ directions — a claim checkable against that skill — re-validating that day's salience-binding fix at a
239
+ sub-Sonnet tier). **Canary, NOT gate**: a PASS adds cheap floor confidence and you still run the Sonnet
240
+ sim; a FAIL never blocks alone — the opus orchestrator triages it as a *real salience gap* (fix the
241
+ rule) vs a *floor-model quirk* (small-model loop/hallucination, per the public "Local AI is not Opus"
242
+ finding + the cheap-oracle ceiling — a small model adds nothing where one grep already settles the
243
+ check). The terminal verdict stays with the frontier (Sonnet sim + opus judge) — no judge-only path, no
244
+ weak-local-judge regression of the judge-robustness principle (mechanical anchor over judge-only verdict).
245
+ The cross-family-panel upgrade spec lives in the private companion store's `handoff/` design note.
246
+
230
247
  **Axis ownership** (each skill is already complete — orchestrator only coordinates):
231
248
 
232
249
  | Axis | Skill | What it catches |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chrono-meta/fh-gate",
3
- "version": "1.4.34",
3
+ "version": "1.4.35",
4
4
  "description": "FH runtime adapters — run FH governance, skills, and agents via Claude or Codex with machine-parseable gates.",
5
5
  "license": "MIT",
6
6
  "keywords": [
@@ -65,7 +65,7 @@ On **cadence-triggered** runs (7d), ask the operator one line before collecting:
65
65
 
66
66
  ## Step 1. Data Collection
67
67
 
68
- Collect from four sources (bash per source in §Collection-Bash):
68
+ Collect from five sources (bash per source in §Collection-Bash):
69
69
 
70
70
  | Source | Method | Cap |
71
71
  |---|---|---|
@@ -73,11 +73,14 @@ Collect from four sources (bash per source in §Collection-Bash):
73
73
  | arxiv | export API, latest by submittedDate | 6 items |
74
74
  | TLDR AI | RSS, title + link | 5 items |
75
75
  | The Batch (deeplearning.ai) | HTML scraping, title + issue slug | 5 items |
76
+ | GeekNews (news.hada.io) | Atom feed (`/rss/news` path), title + link, AI/agent/LLM-relevant | 5 items |
76
77
 
77
- Report progress: `📡 HN 15 items · arxiv 5 items · TLDR 5 items · Batch 5 items collected`
78
+ Report progress: `📡 HN 15 items · arxiv 5 items · TLDR 5 items · Batch 5 items · GeekNews 5 items collected`
78
79
 
79
80
  > **Detail**: See `SKILL_detail.md §Collection-Bash` — curl commands per source with parsing notes — read when executing Step 1.
80
81
 
82
+ **Knowledge-currency augment (on-demand, not weekly-scanned)**: distinct from the trend feeds above, these are fetched when a specific version/fact/spec needs confirming against the model's knowledge cutoff — `docs.anthropic.com` (official Claude/API docs · model IDs · pricing), arxiv (already a feed, also a currency target by ID), and Zenodo (research deposits incl. FH's own). Pull these into context for currency rather than scanning them for trends; in egress-restricted environments (e.g. a company network) route the fetch through the approved bridge (n8n), not a direct call.
83
+
81
84
  ---
82
85
 
83
86
  ## Step 2. Synthesis
@@ -50,7 +50,15 @@ curl -s --max-time 10 -L "https://www.deeplearning.ai/the-batch/"
50
50
 
51
51
  Extract `"title":"..."` + `"slug":"issue-\d+"` pattern → URL: `https://www.deeplearning.ai/the-batch/{slug}/`. Max 5 items.
52
52
 
53
- Report progress: `📡 HN 15 items · arxiv 5 items · TLDR 5 items · Batch 5 items collected`
53
+ ### GeekNews news.hada.io (RSS)
54
+
55
+ ```bash
56
+ curl -s --max-time 8 "https://news.hada.io/rss/news"
57
+ ```
58
+
59
+ Korean dev-news aggregator (HN-equivalent), AI-heavy. **The `/rss/news` path serves an Atom feed** (`<feed>`/`<entry>`, NOT RSS `<item>` — verified 2026-06-20: 50 `<entry>` elements, 0 `<item>`). Parse `<entry>` → `<title>` + `<link href>`; keep AI/agent/LLM/harness-relevant items only. `/rss/news` is a *general* dev-news feed, so if 0 AI-relevant items remain after filtering, **drop GeekNews from this run's progress line rather than padding to 5**. Endpoint verified HTTP 200 (2026-06-20); `/rss/new` and `/rss/topics` 404 — use `/rss/news`. Max 5 items.
60
+
61
+ Report progress: `📡 HN 15 items · arxiv 5 items · TLDR 5 items · Batch 5 items · GeekNews 5 items collected`
54
62
 
55
63
  ---
56
64
 
@@ -102,7 +102,7 @@ Pasting tokens directly in chat exposes them in conversation history; environmen
102
102
 
103
103
  *(Run after Step 0-A·B pre-checks. Output results as environment card, then continue to Step 0-C.)*
104
104
 
105
- CC runs the detection bash automatically (injection pre-flight scan → FH_DIR/CC_HUB_DIR → cwd project info → plugins → MCP → zshrc hook → optional framework detection), then outputs the environment card.
105
+ CC runs the detection bash automatically (injection pre-flight scan → FH_DIR/CC_HUB_DIR → cwd project info → plugins → MCP → zshrc hook → optional framework detection → local LLM runtime, optional), then outputs the environment card.
106
106
 
107
107
  **Stop rule (behavioral)**: if `FH_DIR` is not set, output the bootstrap guidance and **do not proceed to subsequent Steps** — install FH first, then rerun.
108
108
 
@@ -135,7 +135,9 @@ Y (add integration plan items to Step 1) / N (add-only, keep existing rules) / S
135
135
 
136
136
  **[Prerequisite] install-doctor conflict diagnosis (only in environments without install history)**: if `~/.cc_sentinels/{project-name}_wizard_done` doesn't exist (first install), call `/install-doctor --plugin fh-meta` first. CONFLICT/WARNING items → add ❗ markers to Step 2 proposal list. Items the doctor already diagnosed (`FH plugin install` · `zshrc hook` · `.claudeignore`) → map results directly, skip re-diagnosis; all other items → check directly.
137
137
 
138
- Auto-check each item as PASS / MISS / FAIL. Check items: `.claudeignore` · `local_fh_context.md` · `zshrc hook` · `weekly_audit` freshness · `sentinel` setup · FH plugin install · `.git/info/exclude` · MCP plugin · `deep-insight` plugin (optional) · `fh_env_context.jsonc` · `phantom-gate` (Python + AI-output projects only) · domain pattern pack (optional, none ship by default).
138
+ Auto-check each item as PASS / MISS / FAIL. Check items: `.claudeignore` · `local_fh_context.md` · `zshrc hook` · `weekly_audit` freshness · `sentinel` setup · FH plugin install · `.git/info/exclude` · MCP plugin · `deep-insight` plugin (optional) · `fh_env_context.jsonc` · `phantom-gate` (Python + AI-output projects only) · domain pattern pack (optional, none ship by default) · local-LLM offload (optional — surface ONLY if the Step 0 bash emitted the literal line `Local LLM runtime: detected`; absent that line, this item does not exist).
139
+
140
+ **Local-LLM offload (conditional, recommend-only)**: when Step 0 detected a local LLM runtime (Ollama / LM Studio), surface one optional item — route to `/plugin-recommender` for local-model offload tooling. FH recommends, never rebuilds (no-reinvention). Two complementary offload shapes the user picks per workload: **input-side context routing** (a small local model returns line ranges, so the cloud model receives only the dense slices instead of whole files) and **output-side generation delegation** (the local model generates and self-reviews code while the frontier model decomposes and validates). The benefit is tier-dependent — largest in headless/scripted pipelines and on weaker cloud tiers; an interactive session already triages via targeted reads. Local models suit **bounded, well-specified** work (triage, codebase explanation, instructed maintenance), not long-horizon autonomous tasks where small models loop or hallucinate — so the frontier model keeps decomposition and validation. Skip silently when no local runtime is present.
139
141
 
140
142
  > **Detail**: See `SKILL_detail.md §Step1-Checks` — full check table with criteria and verification commands per item — read when executing Step 1.
141
143
 
@@ -128,6 +128,16 @@ FRAMEWORK=""
128
128
  for fw in streamlit django fastapi flask; do
129
129
  if grep -qi "$fw" requirements.txt pyproject.toml 2>/dev/null; then FRAMEWORK="$fw"; echo "Framework: $fw detected"; break; fi
130
130
  done
131
+
132
+ # Local LLM runtime (optional) — gates the conditional local-offload recommendation in Step 1.
133
+ # Ollama default :11434, LM Studio default :1234. Absence is the normal state (no offload item surfaced).
134
+ # Confirm the RESPONSE SHAPE, not just any HTTP 200 — Ollama /api/tags returns {"models":...},
135
+ # LM Studio /v1/models returns {"data":...}; this avoids a non-LLM service squatting the port.
136
+ for url in http://localhost:11434/api/tags http://localhost:1234/v1/models; do
137
+ if curl -sf -m 1 "$url" 2>/dev/null | grep -q '"models"\|"data"'; then
138
+ echo "Local LLM runtime: detected ($url)"; break
139
+ fi
140
+ done
131
141
  ```
132
142
 
133
143
  **Bootstrap guidance when FH_DIR is not set (stop immediately in Step 0):**
@@ -168,6 +178,7 @@ install-wizard — Environment Detection
168
178
  CC Hub: {CC_HUB_DIR or not set}
169
179
  Plugins: {installed plugin list}
170
180
  zshrc hook: {present/absent}
181
+ Local LLM: {runtime + url if detected — omit this row when none}
171
182
  ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
172
183
  ```
173
184
 
@@ -251,6 +262,7 @@ Auto-check the following items based on detected environment. Each item classifi
251
262
  | `fh_env_context.jsonc` | `.claude/rules/fh_env_context.jsonc` exists | `ls .claude/rules/fh_env_context.jsonc` |
252
263
  | `phantom-gate` | **(Python + AI-output projects only)** `phantom-gate` present in `requirements.txt` / `pyproject.toml` | `grep "phantom.gate" requirements.txt pyproject.toml 2>/dev/null` |
253
264
  | `Domain pattern pack applied` | (optional — only when a `{framework}_patterns.md` pack is present; none ship by default) framework-specific pattern checks | `knowledge/shared/{framework}_patterns.md` check (skip if file absent — the normal default) |
265
+ | `local-LLM offload` | (optional — only when Step 0 detected a local LLM runtime) recommend local-model offload tooling, recommend-only | route to `/plugin-recommender` (no install performed here; skip silently if no runtime detected) |
254
266
 
255
267
  ---
256
268
 
@@ -170,6 +170,56 @@ token only *contains* an example substring but is otherwise a real private value
170
170
 
171
171
  ---
172
172
 
173
+ ## Step 3c. Ignore-Verification — the gitignore-mistake safeguard (root-cause, runs before Step 4)
174
+
175
+ Steps 3/3b scan what **is** tracked. This step checks the inverse and the upstream cause: a file you
176
+ *intend* to be private that is **not actually ignored** — the gitignore mistake that becomes tomorrow's
177
+ tracked leak. For each expected-private path, `git check-ignore -v` reports whether it is ignored **and
178
+ by which layer** (committed `.gitignore` · local `.git/info/exclude` · global `core.excludesFile`). A
179
+ path that resolves to no ignore rule is a MISS — surface it before it is ever `git add`ed.
180
+
181
+ ```bash
182
+ # Expected-private set = conventional FH local-only files, EXTENDED with any `# private-path: <path>`
183
+ # lines the operator added to the gitignored pattern source (self-extends per repo — not a frozen
184
+ # operator snapshot). Built one-path-per-line + while-read so it is portable across bash AND zsh
185
+ # (zsh does not word-split an unquoted variable, so `for f in $VAR` would break). A non-existent file
186
+ # is skipped; an all-absent set emits n/a, never a silent pass.
187
+ present=$({ printf '%s\n' CLAUDE.local.md .claude/rules/.public-surface-patterns \
188
+ .claude/rules/local_fh_context.md tracks/_meta/user_adaptation_profile.md
189
+ grep -E '^# private-path:' .claude/rules/.public-surface-patterns 2>/dev/null \
190
+ | sed -E 's/^# private-path:[[:space:]]*//'; } \
191
+ | awk 'NF' | sort -u | while IFS= read -r f; do [ -e "$f" ] && printf '%s\n' "$f"; done)
192
+ [ -z "$present" ] && echo "n/a (no expected-private files present in this repo — add '# private-path:' lines to the pattern source if any exist)"
193
+ printf '%s\n' "$present" | while IFS= read -r f; do
194
+ [ -z "$f" ] && continue
195
+ # Tracked status is tested FIRST: a file can match an ignore rule yet still be force-added
196
+ # (`git add -f`) — the exact ignored-but-committed mechanism behind the PR #109 leak. Tracked wins,
197
+ # so an ignored-but-committed file reports TRACKED (not a false-clean OK).
198
+ if git ls-files --error-unmatch "$f" >/dev/null 2>&1; then
199
+ echo "TRACKED $f (already committed — Step 3 scans its contents; un-track if it must be private: git rm --cached)"
200
+ elif rule=$(git check-ignore -v "$f" 2>/dev/null); then
201
+ echo "OK $f → ignored by [$rule]"
202
+ else
203
+ echo "MISS $f (exists, NOT ignored, NOT tracked — one 'git add .' from a leak; add an ignore rule)"
204
+ fi
205
+ done
206
+ ```
207
+
208
+ - **OK** — ignored; the report names which layer covers it (operator-private files should resolve to
209
+ `.git/info/exclude` or `.gitignore`, never end up tracked).
210
+ - **MISS** — exists but no ignore rule covers it → counts as **🟠 MED** in the Step 4 verdict (a latent
211
+ leak, not yet a breach).
212
+ - **TRACKED** — already committed: Step 3 scans its *contents*; this also flags it for un-tracking if it
213
+ was meant to be private.
214
+
215
+ Why this is the safeguard for **gitignore mistakes** (a wrong assumption about what is ignored):
216
+ `.gitignore` is committed/shared, `.git/info/exclude` is local/personal, and a global `core.excludesFile`
217
+ ignores across all repos — `git check-ignore -v` is the one command that says *which* rule (if any)
218
+ applies, so an "I thought it was ignored" error surfaces here instead of in a public PR (the PR #109
219
+ class of leak). Diagnostic-only: this step never writes — it reports, the operator adds the ignore rule.
220
+
221
+ ---
222
+
173
223
  ## Step 4. Report
174
224
 
175
225
  ```
@@ -180,7 +230,7 @@ public-surface-audit — Operator-Private Token Scan
180
230
  🔴 HIGH ({count})
181
231
  {file}:{line} → {matched token} [class: username | company asset]
182
232
  🟠 MED ({count})
183
- {file}:{line} → {matched token} [class: absolute home path]
233
+ {file}:{line} → {matched token} [class: absolute home path | ignore-MISS (Step 3c)]
184
234
  🟡 LOW ({count})
185
235
  {file}:{line} → {matched token} [class: companion-store | private wiring]
186
236