@chrono-meta/fh-gate 1.4.37 → 1.4.38

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
@@ -520,6 +520,15 @@ harvest-loop Step 0-b uses this file as its source — relying on LLM memory aft
520
520
  ```
521
521
  Closing phrase detected ("wrap up", "done", "good work", "end session", etc.)
522
522
  → ① Check git diff + unpushed commits (status snapshot)
523
+ → ①-b Open-PR sweep — `gh pr list --author @me --state open` (+ `gh search prs --author @me
524
+ --state open` for cross-repo). Classify, **surface-not-auto**: a **self-mergeable** PR
525
+ (operator's own repo, checks green) → *propose merge now* (never auto-merge — HITL); an
526
+ **awaiting-external** PR (other repos / corp review) → *surface for tracking only*. Why here:
527
+ the harness's "마감" ≠ the operator's "마감" — a self-authored PR (PR #111) sat open across
528
+ sessions with un-integrated skills + count drift because no close step surfaced it. Pairs with
529
+ the count-consistency check (which now runs at BOTH the local pre-commit hook AND the plugins/**
530
+ PR-CI merge boundary): the sweep surfaces the PR → merging it → the count-check catches any
531
+ drift at the merge (fh_signal_2026-06-21, gate-locality paired fix).
523
532
  → ② If FH assets changed: harvest-loop
524
533
  → ③ Sync local/gitignored session state to your durable companion store, if you keep one
525
534
  → ④ Memory hygiene — update stale entries + record new session findings
@@ -542,9 +551,10 @@ Closing phrase detected ("wrap up", "done", "good work", "end session", etc.)
542
551
  → ⑤ Card update ← ABSOLUTE LAST: must capture ①–④-b outcomes
543
552
  → ⑥ Commit card + push
544
553
  ```
545
- **Card-last guard**: ①–④-b must ALL complete before ⑤ runs. Any new information produced
546
- during ①–④ (new commits, model changes, new findings) feeds INTO ⑤ — card is never
547
- written mid-sequence and then left open for more work to accumulate after it.
554
+ **Card-last guard**: ①–④-b (incl. ①-b open-PR sweep) must ALL complete before ⑤ runs. Any new
555
+ information produced during ①–④ (new commits from a merged self-PR, model changes, new findings)
556
+ feeds INTO ⑤ — card is never written mid-sequence and then left open for more work to accumulate
557
+ after it.
548
558
 
549
559
  **Mid-session card writes are drafts**: If a task (e.g., a calibration run) internally updates
550
560
  the card, that is a draft. The close chain always re-runs ⑤ to capture post-draft activities.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chrono-meta/fh-gate",
3
- "version": "1.4.37",
3
+ "version": "1.4.38",
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": [
@@ -136,9 +136,23 @@ File: {path}
136
136
  | settings.json JSON syntax error | M-tier |
137
137
  | Hooks in settings.json (PostToolUse/Stop) that don't fire in Agent View | S-tier or M-tier |
138
138
  | Public-surface FH recommendation or default changed — no N-shot measurement evidence traceable in session records or PR body | S-tier |
139
+ | Pre-commit-adjacent gate reads the working tree (cat/glob of a *tracked* path) with no `--staged`/`--cached`/`git show :` on that path, when its verdict is about *what's committed* | S-tier |
139
140
 
140
141
  Hook divergence verdict: 0 hooks = Normal · 1+ hooks (session-end/Stop) = S-tier · 1+ hooks (PostToolUse file writes or external API) = M-tier (data loss risk in Agent View).
141
142
 
143
+ **Index-vs-worktree gate lint** (2026-06-21, gate-locality corollary — `[[feedback_gate_locality_principle]]`):
144
+ a gate whose verdict is about *what is being committed* must read the **staged index**
145
+ (`git ls-files --cached` / `git show :path`), not the working tree (`cat`/glob of a tracked file) —
146
+ else it false-PASSes a commit whose staged content ≠ disk (origin: `count_check.sh` read the worktree
147
+ while the pre-commit hook fired on the index; the sibling `regression_guard` already used `--staged`,
148
+ so the lesson existed but was non-local). Mechanical scan — in the pre-commit hook + the scripts it
149
+ invokes (+ `scripts/*-check.sh`): flag a `cat`/`<`/glob read of a tracked path with no
150
+ `--staged`/`--cached`/`git show :` on that path. **Conditional (NOT universal)**: a gate whose verdict is
151
+ about what *runs/deploys* (pre-push tests, build, an auto-fixer that rewrites the worktree) correctly
152
+ reads the working tree — a line-level `# worktree-intentional:` comment suppresses the flag. FP surface
153
+ (isolated-critic): display/log reads and untracked generated files are not violations → keep advisory
154
+ (S-tier, never M).
155
+
142
156
  ### Step 5. L4 — Connection Diagnosis *(FH only)*
143
157
 
144
158
  - Tracks with no sync in 30+ days → R-tier
@@ -35,35 +35,13 @@ done
35
35
  # Count consistency: stated skill/agent counts vs actual directories.
36
36
  # Drift class recurred 4x on 2026-06-10 alone (local_fh_context 26, plugin.json "3 agents",
37
37
  # README "5 agents", marketplace.json "3 agents") — this makes the check mechanical and permanent.
38
- # Active skill = SKILL.md without a deprecation marker (frontmatter `deprecated: true` or
39
- # "DEPRECATED" in the description block).
40
- count_active() { # count_active <plugin>
41
- local n=0 s
42
- for s in plugins/"$1"/skills/*/SKILL.md; do
43
- [ -f "$s" ] || continue
44
- head -20 "$s" | grep -qE 'deprecated: true|DEPRECATED' || n=$((n+1))
45
- done
46
- echo "$n"
47
- }
48
- count_agents() { ls plugins/"$1"/agents/*.md 2>/dev/null | wc -l | tr -d ' '; }
49
-
50
- meta_sk=$(count_active fh-meta); meta_ag=$(count_agents fh-meta)
51
- com_sk=$(count_active fh-commons); com_ag=$(count_agents fh-commons)
52
- total_sk=$((meta_sk + com_sk)); total_ag=$((meta_ag + com_ag))
53
-
54
- count_check() { # count_check <label> <file> <expected-string>
55
- if grep -q "$3" "$2"; then
56
- echo "PASS count: $1"
57
- else
58
- echo "FAIL count: $1 — expected \"$3\" in $2 (actual: fh-meta ${meta_sk}sk/${meta_ag}ag, fh-commons ${com_sk}sk/${com_ag}ag)"
59
- fail=1
60
- fi
61
- }
62
- count_check "fh-meta plugin.json" plugins/fh-meta/.claude-plugin/plugin.json "${meta_sk} skills + ${meta_ag} agents"
63
- count_check "fh-commons plugin.json" plugins/fh-commons/.claude-plugin/plugin.json "${com_sk} skills"
64
- count_check "marketplace.json fh-meta" .claude-plugin/marketplace.json "${meta_sk} skills + ${meta_ag} agents"
65
- count_check "README header" README.md "${total_sk} skills · ${total_ag} agents"
66
- count_check "local_fh_context fh-meta" templates/local_fh_context.md "(fh-meta, ${meta_sk})"
38
+ # Logic extracted to scripts/count_check.sh so the SAME check also runs at commit time in
39
+ # the pre-commit hook (shift-left, gated on a skills-dir add/remove — fh_signal_2026-06-21
40
+ # gate-locality gap: the check previously lived only here at the publish boundary, so a
41
+ # skill-adding PR could merge with stale counts undetected until the next publish).
42
+ if ! bash scripts/count_check.sh; then
43
+ fail=1
44
+ fi
67
45
 
68
46
  # Referenced-path existence: backtick-quoted repo-relative file refs in the always-loaded
69
47
  # governance surface (CLAUDE.md + .claude/rules/*.md) must exist. Phantom-reference class