@chrono-meta/fh-gate 1.4.49 → 1.4.50
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/CATALOG.md +8 -2
- package/CHEATSHEET.md +1 -1
- package/CLAUDE.md +8 -2
- package/README.md +2 -2
- package/knowledge/shared/harness-core/capability_escalation_consent.md +125 -0
- package/knowledge/shared/harness-core/fh_detail_protocols.md +23 -4
- package/knowledge/shared/harness-core/measurement-integrity-checklist.md +23 -3
- package/knowledge/shared/harness-core/multi_model_sidecar_strategy.md +29 -0
- package/package.json +1 -1
- package/plugins/fh-meta/skills/auto-decorrelation/SKILL.md +10 -1
- package/plugins/fh-meta/skills/context-doctor/SKILL.md +3 -3
- package/plugins/fh-meta/skills/context-doctor/SKILL_detail.md +2 -2
- package/plugins/fh-meta/skills/goal-quench/SKILL.md +17 -10
- package/plugins/fh-meta/skills/harness-doctor/SKILL.md +2 -2
- package/plugins/fh-meta/skills/harvest-loop/SKILL.md +1 -1
- package/plugins/fh-meta/skills/install-wizard/SKILL.md +3 -1
- package/plugins/fh-meta/skills/public-surface-audit/SKILL.md +18 -71
- package/plugins/fh-meta/skills/public-surface-audit/SKILL_detail.md +150 -0
- package/plugins/fh-meta/skills/{skill-splitter → salience-splitter}/SKILL.md +19 -9
- package/plugins/fh-meta/skills/{skill-splitter → salience-splitter}/SKILL_detail.md +6 -6
package/CATALOG.md
CHANGED
|
@@ -8,6 +8,12 @@ AI reads this file first when searching past work. Open individual files for det
|
|
|
8
8
|
|
|
9
9
|
<!-- Add entries in reverse date order (newest at top) -->
|
|
10
10
|
|
|
11
|
+
### 2026-07-07 | forge-harness | #sister-asset, #cross-audit, #revfactory, #harness-100, #agent-composer, #benchmarking, #linkedin, #source-verification, #diffusion-llm
|
|
12
|
+
**File:** tracks/_audit/session_2026_07_07_revfactory-harness.md
|
|
13
|
+
Sister-asset cross-audit of `revfactory/harness` + `revfactory/harness-100` (AX TF lead-recommended benchmarking target) vs FH — their axis = one-shot team-architecture generation + a 200-harness ready library (breadth/quick-start); FH's axis = dynamic composition (`agent-composer`) + governance (4-axis gate, irreversibility floors, continuity), which their pipeline lacks entirely. Plus LinkedIn source-verification for the operator's 2 queued insight links: diffusion-LLM paradigm-shift paper confirmed accurate (ICML 2026 Outstanding Paper Award, JustGRPO, arXiv:2601.15165 via official ICML blog); "Claude Code loop-engineering" post confirmed to be about `k021/claude-code-skills` — the *same* sister-asset Gemini already analyzed, not new content.
|
|
14
|
+
- Decision: no functional import beyond a C-tier team-pattern naming label for `agent-composer` output; FH's governance moat holds (revfactory doesn't compete on that axis). Both LinkedIn links closed.
|
|
15
|
+
- Open: adopt 6-pattern naming in agent-composer (operator HITL); harness-100-style pre-built library stays gated behind the existing 3+-recurrence trigger.
|
|
16
|
+
|
|
11
17
|
### 2026-06-27 | forge-harness | #sister-asset, #cross-audit, #hermes-agent, #nous-research, #self-improving-agent, #skills, #memory, #messaging-gateway
|
|
12
18
|
**File:** tracks/_contrib/session_2026_06_27_hermes-agent-nous-self-improving-cross-audit.md (committed via _contrib consent lane — authored in an ephemeral cloud session where tracks/_audit/ is gitignored/non-durable)
|
|
13
19
|
Sister-asset cross-audit of **Hermes Agent (Nous Research)** vs FH, triggered by a LinkedIn post (esperer) distilling Hermes' official *Tips & Best Practices* (post = faithful doc summary, not original methodology; same summary circulates on Threads). ~90% of Hermes' best-practice surface is already present in FH (persistent memory · auto-skill-from-repetition · skill self-improvement · context economy · delegation · model selection — all grounded to `plugins/*/skills/`), and on the **self-improvement + governance** axis FH is *ahead*: Hermes *advises* "review auto-generated skills," FH *mechanically enforces* it (pre-commit 4-axis gate + steel/phantom-quench + HITL). Key honest finding — most apparent "gaps" dissolve: cron/daemon is a **deliberate FH boundary** (`self_evolution_routine.md` §8 "recommendation surface, not a daemon"), external-memory-providers **already audited** (companion-store pluggable, 2026-06-11). Only genuine absence = **messaging gateway** (Telegram/Slack daily-driver), which is a *delivery channel*, not methodology.
|
|
@@ -177,7 +183,7 @@ CC built-ins utilization imports (operator-approved; video claims verified 9/13
|
|
|
177
183
|
### 2026-06-10 | forge-harness | #ingest-gate, #contradiction-scan, #crossref-lint, #llm-wiki, #karpathy
|
|
178
184
|
**File:** .claude/rules/sync_push_protocols.md (+ harness-doctor SKILL.md, probes.md)
|
|
179
185
|
Karpathy LLM-Wiki sister-audit imports (operator-approved; convergence case n=5, citable primary source): I1 — contradiction scan as Sync step 3 (ingest gate, judged + verify-bidirectional pair): new knowledge grepped against existing claims before indexing, conflicts flagged in both files, old-claim removal is HITL. I2 — harness-doctor L4 knowledge cross-ref lint: no CATALOG entry = S-tier index orphan, no inbound ref = R-tier orphan page. Probes G-SYNC-01/G-LINT-01 added (30 total).
|
|
180
|
-
- Decision: scale escape (W1) deliberately NOT built — watch-item with trigger (CATALOG hundreds of entries / repeated search misses); operator-preferred first remedy =
|
|
186
|
+
- Decision: scale escape (W1) deliberately NOT built — watch-item with trigger (CATALOG hundreds of entries / repeated search misses); operator-preferred first remedy = salience-splitter-style CATALOG split-mapping, RAG hybrid only after that.
|
|
181
187
|
- Open: npm republish (harness-doctor SKILL.md shipped) — folded into the open 1.4.8 handoff.
|
|
182
188
|
|
|
183
189
|
### 2026-06-10 | forge-harness | #golden-probes, #offline-eval, #doc-code-coupling, #anthropic-4layer
|
|
@@ -282,7 +288,7 @@ Post-merge micro R-tier cleanup: corrected two prompt-regression probe expectati
|
|
|
282
288
|
|
|
283
289
|
### 2026-06-03 | forge-harness | #goal-quench, #skill-evolution, #mode-ladder, #sidecar-routing
|
|
284
290
|
**File:** plugins/fh-meta/skills/goal-quench/SKILL.md
|
|
285
|
-
Evolved goal-quench into a fluid core→pro→max mode ladder. Core: token-budget-gate + pipeline-conductor --quick; pro: +context-doctor +agent-composer; max: +plugin-recommender +cross-ecosystem-synergy-detection. Phase-1 budget verdict auto-recommends mode. Ran full-harness dogfood sweep (33 skills): fixed phantom refs, dead blocks, stale agent forks (4 deleted), trigger collision, and 3
|
|
291
|
+
Evolved goal-quench into a fluid core→pro→max mode ladder. Core: token-budget-gate + pipeline-conductor --quick; pro: +context-doctor +agent-composer; max: +plugin-recommender +cross-ecosystem-synergy-detection. Phase-1 budget verdict auto-recommends mode. Ran full-harness dogfood sweep (33 skills): fixed phantom refs, dead blocks, stale agent forks (4 deleted), trigger collision, and 3 salience-splitter splits.
|
|
286
292
|
- Decision: RED tier reframed as max-mode decomposition on-ramp, not hard block
|
|
287
293
|
|
|
288
294
|
### 2026-06-02 | _audit | sister-asset, token-efficiency, compression, headroom
|
package/CHEATSHEET.md
CHANGED
|
@@ -511,7 +511,7 @@ Claude agents feature
|
|
|
511
511
|
|---|---|---|
|
|
512
512
|
| `install-wizard` | First-install onboarding (zshrc, sentinels, the FH self-gate) | "first-time setup", "run the install wizard" |
|
|
513
513
|
| `hub-cc-pr-reviewer` | Reads a PR diff → 8-matrix baseline-consistency check → review comment + merge call | "review this PR", "check this diff" |
|
|
514
|
-
| `
|
|
514
|
+
| `salience-splitter` | Splits an over-large SKILL.md that "does everything" into scoped files | "this skill is bloated", "SKILL.md too large", "split this skill" |
|
|
515
515
|
|
|
516
516
|
### Agents (sub-agents, dispatched — not slash commands)
|
|
517
517
|
|
package/CLAUDE.md
CHANGED
|
@@ -142,7 +142,7 @@ Compose session-card candidates **into door ③ (field) and the 🔧 door (FH-de
|
|
|
142
142
|
|
|
143
143
|
**Identity marker**: every greeting response (Step ②) opens with 🐿️ then an identity-revealing welcome line **on the same line** (a space after 🐿️; exact count not significant — the renderer collapses it — the invariant is *same-line*, not 🐿️ alone) — new / exploratory = "Welcome to FH." · returning = "Welcome back to FH." · operator (FH-dev state) = "The FH operator — good to see you." It is embedded in all skeletons above (do not strip it when composing doors); the exploratory branch template (`fh_detail_protocols.md` Step 2) uses the "Welcome to FH." line.
|
|
144
144
|
|
|
145
|
-
**Guards**: explicit task-entry utterance → skip onboarding · once per session · code/debug requests → start working directly · project routing is a suggestion, mention at most once
|
|
145
|
+
**Guards**: explicit task-entry utterance → skip onboarding **menu** (the door skeleton / greeting) — but this **never skips the Mode D companion-store freshness load** (pull + INDEX read + card-vs-commit reconcile); that is a data-load, not the menu, and it fires even when the first message is a task (measured miss 2026-07-05: task-first entry skipped the companion-store pull → stale memory → wrong recommendations; now hook-backed via `scripts/fh_session_load.sh`, see `modes_and_value.md §Session-start freshness`) · once per session · code/debug requests → start working directly · project routing is a suggestion, mention at most once
|
|
146
146
|
**Metadata-is-not-intent guard**: the trigger is the user's **typed message only**. Session metadata — branch name (auto-derived from the first message, e.g. `claude/korean-greeting-*`), repo name, file paths — is **never** a task spec and never suppresses or redirects the greeting trigger. A bare greeting fires onboarding even when the branch name looks like a feature request; if the only "task" signal lives in metadata and not in what the user typed, treat the message as a greeting and run the greeting branch + door skeleton above.
|
|
147
147
|
|
|
148
148
|
## New Skill Creation Pre-Commit Gate
|
|
@@ -285,6 +285,12 @@ unknown) and surface **one line** — then proceed, never block:
|
|
|
285
285
|
inviolable; a pin is not a cap — tier-floor resolution §Floor governance) · field-project operation
|
|
286
286
|
sessions (no FH asset modification) never see this notice — the Sonnet default stays friction-free.
|
|
287
287
|
|
|
288
|
+
> **Related — capability-escalation consent**: whether a session actually *escalates* to a stronger
|
|
289
|
+
> model or a cross-family sidecar (not just this advisory notice) is governed separately by
|
|
290
|
+
> `knowledge/shared/harness-core/capability_escalation_consent.md` — the negotiated-consent protocol
|
|
291
|
+
> (UAP `sidecar_consent`/`floorup_consent`) that decides ask-once vs. no-surprise floor-up/sidecar use.
|
|
292
|
+
> This notice is the passive advisory; that doc is the active escalation gate.
|
|
293
|
+
|
|
288
294
|
## Field-Harness Load-Bearing Change Gate (cross-family, pre-merge)
|
|
289
295
|
|
|
290
296
|
The 4-axis gate above fires on **FH asset** changes. But the correlated blind spot it guards —
|
|
@@ -537,7 +543,7 @@ Proposal format: `"I see [X]. Want me to run /[skill] to [one-line description]?
|
|
|
537
543
|
| "add this MCP server", "mount this MCP", "mcp.json에 추가", "connect this tool server" (external-MCP mount intent — **proactive**, fire *before* first tool call; mount intent only — a failing/erroring mounted server is `/mcp-circuit-breaker`'s row above) | `templates/.claude/rules/mcp_tool_gating.md` (name-keyed ask/allow table — never trust server annotations or names; fill §3 at mount time) |
|
|
538
544
|
| "token budget", "how expensive", "estimate tokens", "will this cost a lot" | `/token-budget-gate` |
|
|
539
545
|
| "did my rule change break anything", "regression check", "test harness changes" | `/prompt-regression` |
|
|
540
|
-
| "SKILL.md too large", "split this skill", "skill is bloated", "skill file too long" | `/
|
|
546
|
+
| "SKILL.md too large", "split this skill", "skill is bloated", "skill file too long" | `/salience-splitter` |
|
|
541
547
|
| "review for the team", "CTO review", "decision-maker", "share with leadership", "approval deck" | `/apex-review` |
|
|
542
548
|
| "run full pipeline", "verify everything", "end-to-end sweep", "chain all verifications" | `/pipeline-conductor` |
|
|
543
549
|
| "help me write a prompt", "build a prompt", "improve this prompt", "prompt template" | `/meta-prompt-builder` |
|
package/README.md
CHANGED
|
@@ -214,7 +214,7 @@ two more signatures keep it running: `harvest-loop` (each session's lessons beco
|
|
|
214
214
|
| `token-budget-gate` *(fh-commons)* | Pre-task token cost estimate | "How expensive is this?" |
|
|
215
215
|
| `mcp-circuit-breaker` *(fh-commons)* | MCP tool failure pattern detection | "MCP keeps failing" |
|
|
216
216
|
| `quench-challenger` *(fh-commons)* | Adversarial pressure-test agent | "Challenge this with a devil" |
|
|
217
|
-
| *(+ additional assets)* | marketplace-gate · contention-layer · edit-manifest · fact-checker · goal-quench · hub-persona-auditor · install-doctor · memory-hygiene · persona-innovator · prompt-regression · public-surface-audit ·
|
|
217
|
+
| *(+ additional assets)* | marketplace-gate · contention-layer · edit-manifest · fact-checker · goal-quench · hub-persona-auditor · install-doctor · memory-hygiene · persona-innovator · prompt-regression · public-surface-audit · salience-splitter | |
|
|
218
218
|
|
|
219
219
|
| Active count | Diagnosis |
|
|
220
220
|
|:---:|---|
|
|
@@ -233,7 +233,7 @@ two more signatures keep it running: `harvest-loop` (each session's lessons beco
|
|
|
233
233
|
| Gate / Guard | `token-budget-gate` · `asset-placement-gate` · `marketplace-gate` |
|
|
234
234
|
| Discovery | `plugin-recommender` · `cross-ecosystem-synergy-detection` · `frontier-digest` · `verify-bidirectional` |
|
|
235
235
|
| Content / Simulation | `sim-conductor` · `apex-review` · `meta-prompt-builder` · `deep-clarify` |
|
|
236
|
-
| Setup | `install-wizard` · `hub-cc-pr-reviewer` · `
|
|
236
|
+
| Setup | `install-wizard` · `hub-cc-pr-reviewer` · `salience-splitter` |
|
|
237
237
|
|
|
238
238
|
> **Full phrasebook** — every skill + agent with its one-line definition and the plain-language phrase
|
|
239
239
|
> that triggers it: [`CHEATSHEET.md` §12](CHEATSHEET.md#12-skills--agents--what-each-does-and-what-to-say).
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# Capability-Escalation Consent Protocol
|
|
2
|
+
|
|
3
|
+
> **Principle**: any escalation that raises **cost or trust surface** — recruiting a **cross-family
|
|
4
|
+
> sidecar** (external model families see the work) or a **model-tier floor-up** (Sonnet → Opus, higher
|
|
5
|
+
> $/token) — is **consent-gated and negotiated up front**, never sprung silently. A user who was never
|
|
6
|
+
> asked, then finds a paid/external escalation happened, feels **blindsided (뒤통수)**. The harness
|
|
7
|
+
> must run **intelligently on Claude Code alone at the Sonnet floor** for anyone who declined, using
|
|
8
|
+
> **sub-agents** in place of cross-family sidecars — as a *first-class mode*, not a degraded one.
|
|
9
|
+
|
|
10
|
+
This is a **규약 (convention)**, not a per-call decision: the same answer holds for the whole session
|
|
11
|
+
once settled, and is **remembered across sessions** (UAP) so it is asked at most once.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Two escalation axes (same consent shape)
|
|
16
|
+
|
|
17
|
+
| Axis | Escalation | Why it needs consent | Floor when declined |
|
|
18
|
+
|---|---|---|---|
|
|
19
|
+
| **(a) Cross-family sidecar** | recruit codex / agy / gemini / local-4090 as a verifier | work leaves the Claude boundary (external family sees it) + external billing | **Tier-3 CC-only sub-agent** (isolation-decorrelation, honest same-family note) |
|
|
20
|
+
| **(b) Model-tier floor-up** | Sonnet → Opus for a depth-heavy turn | higher $/token (Opus ≈ 3–5× Sonnet); the operator's real cost lever | **stay at Sonnet** (the established minimum-recommended floor) |
|
|
21
|
+
|
|
22
|
+
**Sonnet = minimum-recommended model is already established** — so the declined-floor is safe: the
|
|
23
|
+
harness is *designed* to run well at Sonnet, not crippled by it (`[[feedback_harness_aerodynamics_perceived_perf]]`).
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## When consent is settled — two entry points
|
|
28
|
+
|
|
29
|
+
### 1. Onboarding negotiation (install-wizard) — the no-surprise path
|
|
30
|
+
|
|
31
|
+
install-wizard **explicitly negotiates both axes** at setup, as named items:
|
|
32
|
+
- *"Allow cross-family sidecars (codex/agy/local) for adversarial verification of load-bearing changes? They add external-family decorrelation but external billing applies."* → records `sidecar_consent`.
|
|
33
|
+
- *"Allow automatic Sonnet→Opus floor-up on depth-heavy turns? Opus is ~3–5× the cost; declining keeps you at the Sonnet floor and asks per-occasion instead."* → records `floorup_consent`.
|
|
34
|
+
|
|
35
|
+
Settling this at onboarding is the **whole point**: the escalation is then *expected*, never a surprise
|
|
36
|
+
on the bill or the egress log.
|
|
37
|
+
|
|
38
|
+
### 2. Runtime ask-once (for anyone who skipped onboarding setup) — the graceful path
|
|
39
|
+
|
|
40
|
+
A user who skipped explicit setup is **not** auto-escalated. Instead, the **first time** an escalation
|
|
41
|
+
is actually needed:
|
|
42
|
+
- **Ask once**, at the moment of need, framed with the cost/trust reason:
|
|
43
|
+
*"This turn needs Opus depth (higher cost) — proceed at Opus, or stay at Sonnet?"* /
|
|
44
|
+
*"This load-bearing change is best verified cross-family (external billing) — recruit a sidecar, or verify with CC sub-agents only?"*
|
|
45
|
+
- **Accept** → record consent (UAP), proceed, no re-ask.
|
|
46
|
+
- **Decline** → record decline (UAP), **mark the escalation "recommended only"** going forward (surface
|
|
47
|
+
it as a one-line recommendation when relevant, **never a re-nag**), and **proceed at the floor**
|
|
48
|
+
(Sonnet / Tier-3 sub-agent).
|
|
49
|
+
|
|
50
|
+
The ask fires **once per axis**; the answer is remembered. A declined axis becomes a standing floor, not
|
|
51
|
+
a per-turn question.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## The declined mode is first-class, not "degraded"
|
|
56
|
+
|
|
57
|
+
When an axis is declined (or no sidecar is reachable), the fallback is **the user's chosen normal
|
|
58
|
+
operating mode**, and must be framed that way:
|
|
59
|
+
|
|
60
|
+
- **Cross-family declined → Tier-3 CC-only sub-agent verification.** Multiple **isolated** Claude
|
|
61
|
+
sub-agents adversarially verify (isolation-decorrelation), with an **honest same-family note**
|
|
62
|
+
("no cross-family diversity — verification is isolation-decorrelated only"). This is intelligent
|
|
63
|
+
operation, **not** "reduced value / degraded" language. (`[[feedback_judge_robustness_mechanical_anchor]]`
|
|
64
|
+
still holds: the governor keeps the terminal verdict + a mechanical anchor.)
|
|
65
|
+
- **Floor-up declined → stay at Sonnet**, run the turn with good harness structure. No apology framing.
|
|
66
|
+
|
|
67
|
+
**Reframe rule**: the Sidecar Resolution Protocol's Tier-3 line and auto-decorrelation's degrade ladder
|
|
68
|
+
must not read "no diversity; reduced value" for a *declined* user — that pathologizes their choice.
|
|
69
|
+
Distinguish **declined** (chosen floor — first-class) from **unavailable-but-wanted** (genuine
|
|
70
|
+
degrade-with-note). Only the latter carries the degrade framing.
|
|
71
|
+
|
|
72
|
+
### Reconciliation with the corp fail-closed invariant
|
|
73
|
+
|
|
74
|
+
The pmh corp degrade-invariant (`local_pmh_context.md` auto-decorrelation Step 6) says a load-bearing
|
|
75
|
+
change with **no reachable cross-family panel → NOT-CONVERGED / ask operator**. That is the
|
|
76
|
+
**unavailable-but-expected** case (consent given, panel down). The **declined** case is different: the
|
|
77
|
+
user opted out, so Tier-3 sub-agent verification **is** the standing bar (with the honest same-family
|
|
78
|
+
note), and load-bearing changes proceed under it — not blocked. Membership: `floorup_consent`/
|
|
79
|
+
`sidecar_consent == declined` in the UAP routes to the first-class floor; absence of a *wanted* panel
|
|
80
|
+
routes to fail-closed.
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## UAP persistence (behavioral pref — never domain content)
|
|
85
|
+
|
|
86
|
+
`operational_adaptation.md` UAP gains two fields:
|
|
87
|
+
- `sidecar_consent: accepted | declined | unset`
|
|
88
|
+
- `floorup_consent: accepted | declined | unset`
|
|
89
|
+
|
|
90
|
+
**READ** (session start / at point of need): `declined` → route to floor, surface as recommendation
|
|
91
|
+
only, no re-nag. `accepted` → escalation available (still per-need, no auto-run). `unset` → ask-once
|
|
92
|
+
on first need (runtime path above).
|
|
93
|
+
**WRITE**: on onboarding settle, or on the first runtime accept/decline.
|
|
94
|
+
|
|
95
|
+
Ephemeral/cloud sessions (UAP wiped) → operate from the **Sonnet floor + CC-only** default (the safe
|
|
96
|
+
floor), do not fabricate consent.
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Cost lens (why this IS the cost-governance mechanism)
|
|
101
|
+
|
|
102
|
+
The floor-up consent prompt is **the operator's cost lever made explicit** (measured: Sonnet-economized
|
|
103
|
+
≈ 34× subscription; Opus-full 40–60×, `cost_report_2026-07-07`). Default Sonnet floor + escalate-Opus-
|
|
104
|
+
**only-where-depth-pays**-with-consent is precisely "amortize Opus on the turns that earn it." Pair with
|
|
105
|
+
a **free internal-model execution lane** where the environment has one (`[[feedback_multimodel_3lane_architecture]]`)
|
|
106
|
+
to offload exec cost off the paid API entirely. The protocol turns hard-won economizing into a mechanical default.
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## Done When
|
|
111
|
+
|
|
112
|
+
- **Both axes negotiated at onboarding** (install-wizard names sidecar + floor-up as consent items). *[mandatory-pass — grep install-wizard for both items]*
|
|
113
|
+
- **Runtime ask-once wired** for `unset` consent at first need; decline → recommend-only + floor, no re-nag. *[judged — pair: Sonnet target-tier blind sim of a skipped-onboarding session hitting first floor-up]*
|
|
114
|
+
- **UAP fields present + READ applied** (`sidecar_consent`, `floorup_consent`). *[mandatory-pass — grep operational_adaptation.md]*
|
|
115
|
+
- **Declined-mode reframed first-class** (no "degraded/reduced-value" language on a declined user's Tier-3 path). *[judged — pair: challenger reads auto-decorrelation + Sidecar Resolution for pathologizing language]*
|
|
116
|
+
- **Corp fail-closed reconciled** (declined ≠ unavailable-but-wanted). *[judged — pair: the target-tier sim above exercises both branches]*
|
|
117
|
+
|
|
118
|
+
## Guards
|
|
119
|
+
|
|
120
|
+
- **Human override inviolable** — a consent is a default, never a cap; the operator can always force a
|
|
121
|
+
tier/sidecar for a given turn (`[[feedback_verify_before_downgrade]]` floor governance).
|
|
122
|
+
- **Never auto-switch the session model** — the floor-up ASK proposes; the human acts (`/model`). The
|
|
123
|
+
protocol never flips the model itself.
|
|
124
|
+
- **Sonnet floor is a floor, not a ceiling** — declined-floor-up still escalates *within* Sonnet's
|
|
125
|
+
harness depth (sub-agents, good structure); it does not cap capability, only cost/trust surface.
|
|
@@ -37,12 +37,31 @@ ls ../ | grep -iE '(forge-harness|meta-harness|-harness|-hub)'
|
|
|
37
37
|
ls .claude/registry/LOCAL_SKILL_REGISTRY.md 2>/dev/null
|
|
38
38
|
```
|
|
39
39
|
- File exists and modified within 7 days → load into session
|
|
40
|
-
- Missing or older than 7 days → regenerate
|
|
40
|
+
- Missing or older than 7 days → regenerate.
|
|
41
|
+
|
|
42
|
+
**No hardcoded root — derive the install location (users install FH anywhere).** The projects root is
|
|
43
|
+
the *parent of the FH repo*, discovered at runtime, never a literal `~/projects` / `~/PycharmProjects`
|
|
44
|
+
(a hardcoded root silently returns 0 on any machine whose layout differs — the 2026-07-05 dead-path
|
|
45
|
+
`fail-open` bug: `find ~/projects` on a `~/PycharmProjects` machine → 0 catches → the registry is
|
|
46
|
+
overwritten empty and cross-project summon goes dark):
|
|
41
47
|
```bash
|
|
42
|
-
|
|
43
|
-
|
|
48
|
+
HUB="${CLAUDE_PROJECT_DIR:-$(pwd)}" # FH 레포 위치 (설치 위치 무관, 감지)
|
|
49
|
+
ROOT="$(cd "$HUB/.." 2>/dev/null && pwd)" # 형제 프로젝트가 사는 부모 = 프로젝트 루트
|
|
50
|
+
# 두 레이아웃 모두 포착: .claude/skills/*/SKILL.md AND 루트-레벨 */SKILL.md (예: gstack).
|
|
51
|
+
# vendored(.venv·site-packages·node_modules·.git) 제외 — 없으면 playwright/streamlit 스킬까지 삼킴.
|
|
52
|
+
FOUND="$(find "$ROOT" -name SKILL.md \
|
|
53
|
+
-not -path "*/.venv/*" -not -path "*/site-packages/*" \
|
|
54
|
+
-not -path "*/node_modules/*" -not -path "*/.git/*" \
|
|
55
|
+
-not -path "$HUB/*" 2>/dev/null)" # exclude FH's own subtree by DERIVED path, not a name-literal (works when FH is cloned under any dir name)
|
|
44
56
|
```
|
|
45
|
-
|
|
57
|
+
Then **fail-closed** (irreversible-ish: a silent empty overwrite blinds the bus): if `$FOUND` is empty
|
|
58
|
+
**and** the existing registry has >0 entries, do **not** overwrite — flag `⚠️ scan returned 0 (root=$ROOT);
|
|
59
|
+
kept existing registry` and skip the rewrite. Only rewrite when the scan is non-empty (or the registry
|
|
60
|
+
was absent). Group by project (parent dir name). Record per skill: name · path · description · trigger
|
|
61
|
+
phrases · `requires_cwd` · `direct-executable` · `origin(FH|project|external)`+trust. **Non-FH skills are
|
|
62
|
+
propose-only (ask-tier), never auto-run** — a cross-project skill body is an injection surface. Propose
|
|
63
|
+
cross-project skills when a request maps to the registry. Scan once per session. (Detection belongs at
|
|
64
|
+
install too — `/install-wizard` records HUB/ROOT so the runtime never guesses; see install-wizard.)
|
|
46
65
|
|
|
47
66
|
### Step 2 — Active Proposal
|
|
48
67
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Measurement-Integrity Checklist — cross-model measurement pre-flight
|
|
2
2
|
|
|
3
3
|
> A cross-model measurement is only trustworthy if its **instrument** is verified first.
|
|
4
|
-
> Measurement integrity is a *precondition*, not a result.
|
|
4
|
+
> Measurement integrity is a *precondition*, not a result. Four observed failure modes, each with a
|
|
5
5
|
> concrete countermeasure. Consult this before any FH measurement that compares models (sims, sidecar
|
|
6
6
|
> comparisons, capability-equalizer runs, the-bible model panels, A6-class experiments).
|
|
7
7
|
|
|
@@ -16,6 +16,7 @@ becomes a gate other skills invoke, revisit the weight.
|
|
|
16
16
|
| 1 | **Silent model fallback** — passing a model *slug* silently resolved to a weaker model (e.g. an `agy` slug fell back to Flash) instead of the intended one. The run *looks* like the named model but isn't. | **Pin the display name, not the slug** (e.g. `"Gemini 3.1 Pro (High)"`, not a bare slug). Confirm the resolved identity, don't assume the slug binds. |
|
|
17
17
|
| 2 | **Non-deterministic borderline verdicts** — contested/borderline cases flip across runs (observed: haiku 4/4 flip; flagship models flip too — flipping is **not** a tier signal). A single draw is noise, not a measurement. | **reps ≥ 3 on any borderline/contested verdict.** A single run on a contested case is inadmissible. Report the flip pattern (STABLE vs FLIP), not just the modal verdict. |
|
|
18
18
|
| 3 | **Generic self-identity probe** — a probe any model passes ("are you working? → OK") proves nothing about *which* model answered. | **Use a discriminating probe** — one that two different models answer *differently*. A generic-pass probe is invalid. The probe is a **pattern, not a fixed string**: a probe that discriminates Opus 4.8 from Sonnet 4.6 today may both-pass a future model generation, so **re-validate the probe each model generation** (same staleness class `memory-hygiene` exists to catch). |
|
|
19
|
+
| 4 | **Serving-path / quantization variance** — the *same* display-name model served over two different backends (different quantization/infra) is a **different instrument** and yields materially different measurements. Observed: one GLM-5.2 model family gave effect-size delta **+0.21** when served via an internal NVFP4-quantized deployment vs **+0.08** via an OpenRouter relay — same model name, ~2.6× different effect (n=864, reps≥3). A correctly-pinned display name (item #1) is **necessary but not sufficient**. | **Pin *and record* the serving path** — backend host + quantization, not just the display name. Two runs are comparable only if the serving path matches; a name match across different infra is an implicit apples-to-oranges. When you cannot hold it fixed, **report the serving path as a measured variable**, not a constant. |
|
|
19
20
|
|
|
20
21
|
## Why these are entangled (and why they matter beyond their own scope)
|
|
21
22
|
|
|
@@ -28,10 +29,17 @@ single-draw artifact. Item #3 (discriminating probe) **embodies** the judge-robu
|
|
|
28
29
|
mechanical-anchor principle — don't trust self-reported identity, prove it discriminatingly
|
|
29
30
|
([[feedback_judge_robustness_mechanical_anchor]]).
|
|
30
31
|
|
|
32
|
+
Item #4 (serving-path variance) **sharpens** item #1 into a two-part identity: #1 catches the *wrong
|
|
33
|
+
model* (a slug that fell back); #4 catches the *right model on the wrong instrument* (a correct name
|
|
34
|
+
served over a different quantization/backend). The verified identity a measurement records is therefore
|
|
35
|
+
**name + serving path**, not name alone — a family-decorrelation claim (cross-family sidecar) is only
|
|
36
|
+
sound once the serving path of each family is itself pinned, else "different family" silently smuggles
|
|
37
|
+
"different infra" ([[reference_measurement_serving_path_variance]]).
|
|
38
|
+
|
|
31
39
|
## Done When
|
|
32
40
|
|
|
33
|
-
- The checklist enumerates all
|
|
34
|
-
*Check class: mandatory-pass (binary —
|
|
41
|
+
- The checklist enumerates all four failure modes, each with its countermeasure.
|
|
42
|
+
*Check class: mandatory-pass (binary — four items present, each with a countermeasure).*
|
|
35
43
|
- The probe item specifies a **discriminating** test and rejects generic probes.
|
|
36
44
|
*Check class: judged, pair: a probe that two different models both pass must FAIL this check; a
|
|
37
45
|
discriminating one must distinguish them.*
|
|
@@ -57,3 +65,15 @@ mechanical log.
|
|
|
57
65
|
ambiguity). Sister findings: [[feedback_correlated_blindspot_union_over_majority]] (reps≥3 prerequisite),
|
|
58
66
|
[[feedback_judge_robustness_mechanical_anchor]] (discriminating-probe = mechanical anchor),
|
|
59
67
|
[[reference_agy_model_catalog]] (display-name pin — agy slug fallback documented there).
|
|
68
|
+
|
|
69
|
+
**#4 added** (2026-07-05): serving-path variance surfaced in a cross-family verdict-invariance run
|
|
70
|
+
(n=864, borderline fixtures × 2 conditions × K=6 paraphrase × reps≥3). An identical GLM-5.2 model name
|
|
71
|
+
served over an internal NVFP4-quantized deployment vs an OpenRouter relay gave +0.21 vs +0.08
|
|
72
|
+
effect-size delta — quantifying that "same model name ⇒ same measurement" is false. Provenance +
|
|
73
|
+
generalizable finding: [[reference_measurement_serving_path_variance]].
|
|
74
|
+
|
|
75
|
+
**External corroboration** (2026-07): the local-LLM community independently reports the same hazard —
|
|
76
|
+
practitioners conflate "running model X" with running a *pruned/quantized derivative* of X (aggressive
|
|
77
|
+
low-bit quantization + expert pruning measurably degrade long-context quality while the model *name* is
|
|
78
|
+
unchanged). This is a general measurement pitfall, not FH-specific: a leaderboard or replication that
|
|
79
|
+
pins only the display name silently compares different instruments across serving paths.
|
|
@@ -167,6 +167,35 @@ buff and degrades that model's realized intelligence** — not just Claude's. Th
|
|
|
167
167
|
is autocomplete/QA only, which is exactly its demoted role. (Derived 2026-07-03, operator + cross-vendor
|
|
168
168
|
Gemini concurrence; extends the governor=native-CC point to every vendor.)
|
|
169
169
|
|
|
170
|
+
### Batch-judging corollary — the native harness is for interactive/agentic work, not batch scoring
|
|
171
|
+
|
|
172
|
+
The vendor-native harness gives a model its highest capability for **interactive, agentic** tasks
|
|
173
|
+
(repo-grounded audit, multi-step design, tool-use) — but that *same* agentic loop is a **liability for
|
|
174
|
+
high-volume batch judging**: a deterministic verdict emitted over N fixtures, where there is nothing for a
|
|
175
|
+
tool-use loop to do. Measured 2026-07-04 (H1 verdict-invariance run): the native `codex exec` spins a full
|
|
176
|
+
agentic session per judge (hooks + reasoning ≈ an order of magnitude more tokens than a bare completion),
|
|
177
|
+
and native `agy -p` (once its headless permission-wait is cleared) returns *agentic prose* — a "Summary of
|
|
178
|
+
Work" — rather than a parseable last-line verdict. Both **complete**, but at a cost/parse profile wrong for
|
|
179
|
+
batch.
|
|
180
|
+
|
|
181
|
+
So the dispatch splits by *shape of the task*, not just by family:
|
|
182
|
+
|
|
183
|
+
- **Batch cross-family judging** (steel-quench Step 0.6 verdict-invariance, auto-decorrelation over many
|
|
184
|
+
items, any fixed-fixture flip count) → **clean completion APIs** (OpenRouter, model pinned by
|
|
185
|
+
*display-name* + `served`-field silent-route check) **+ free local** (a 4090 ollama endpoint). Clean,
|
|
186
|
+
cheap, parseable, per-call pinnable. *Caveat*: a local thinking model needs a large enough output budget
|
|
187
|
+
or it truncates inside `<think>` and emits an empty verdict — a config axis, not a capacity limit.
|
|
188
|
+
- **Interactive / agentic verification** (repo-grounded catching, the divergence audits where cross-family
|
|
189
|
+
disagreement *localizes* a bug) → the **native CLIs** (`codex`, `agy`/Antigravity), where the harness
|
|
190
|
+
earns its overhead.
|
|
191
|
+
|
|
192
|
+
This is **not** a contradiction of the harness-depth thesis — it *is* it. The harness lifts capability
|
|
193
|
+
exactly where judgment + tools + iteration matter; for a one-shot self-contained verdict the loop has no
|
|
194
|
+
work, so its depth becomes pure cost. Pick the naked API for batch scoring, the native harness for agentic
|
|
195
|
+
audit. (Derived 2026-07-04, operator + H1 measurement; the batch-side dual of the vendor-native thesis
|
|
196
|
+
above. The native-harness Gemini path via `agy` is headless-usable again once tool-permission auto-proceed
|
|
197
|
+
is set — see [[reference_agy_model_catalog]] for the pin/permission mechanics.)
|
|
198
|
+
|
|
170
199
|
**Maintenance-Cost Rule** — a compatibility layer is cheap as a *thin entrypoint*, expensive when it
|
|
171
200
|
*duplicates canonical knowledge*. The test:
|
|
172
201
|
|
package/package.json
CHANGED
|
@@ -100,11 +100,20 @@ Local 4090 = **canary tier** (evidence-of, never terminal verdict).
|
|
|
100
100
|
|
|
101
101
|
## Step 6 — Degrade ladder (the intelligent scale-down)
|
|
102
102
|
|
|
103
|
+
**Consent branch first — declined ≠ degraded** (`[[capability_escalation_consent]]`): if the UAP has
|
|
104
|
+
`sidecar_consent: declined`, do **not** probe/recruit — route straight to **Tier-3 CC-only sub-agent
|
|
105
|
+
verification** (multiple isolated Claude sub-agents, isolation-decorrelation) as a **first-class chosen
|
|
106
|
+
mode**, with an honest *same-family* note but **no "reduced value / degraded" framing** — the user chose
|
|
107
|
+
this floor. `unset` → ask-once at first load-bearing need (accept → proceed; decline → record + this
|
|
108
|
+
branch). Only proceed to the discovery ladder below when consent is `accepted`.
|
|
109
|
+
|
|
103
110
|
1. frontier cross-family CLI present → recruit it (decorrelated, at-floor) — best.
|
|
104
111
|
2. only local 4090 present → canary pre-screen + in-session opus governor (canary, not full decorrelation).
|
|
105
112
|
3. nothing present → in-session same-family + **honest below-floor/same-family note** (residual named).
|
|
106
113
|
|
|
107
|
-
Env non-determinism (CLI presence varies) → **silent degrade, never hard-fail**.
|
|
114
|
+
Env non-determinism (CLI presence varies) → **silent degrade, never hard-fail**. Distinguish this
|
|
115
|
+
**unavailable-but-wanted** case (consent given, panel down → degrade-with-note; for a *load-bearing corp*
|
|
116
|
+
surface, fail-closed per `local_pmh_context.md`) from the **declined** case above (chosen floor, first-class).
|
|
108
117
|
|
|
109
118
|
## Step 7 — Output
|
|
110
119
|
|
|
@@ -117,7 +117,7 @@ Run the audit bash (§Step-Bash) and apply thresholds:
|
|
|
117
117
|
| CLAUDE.md | Exceeds 300 lines | Section-by-section compression / move completed sections to archive |
|
|
118
118
|
| MEMORY.md | Exceeds 180 lines | Check entry count + move `✅ CLOSED` items to archive section |
|
|
119
119
|
| memory/*.md single file | Exceeds 30K (300 lines) | Suggest splitting accumulated history into separate files |
|
|
120
|
-
| SKILL.md (any) | > 300 lines AND no SKILL_detail.md | Propose `/
|
|
120
|
+
| SKILL.md (any) | > 300 lines AND no SKILL_detail.md | Propose `/salience-splitter` — governance-semantic split (not compression); compression removes content, splitting routes it on-demand |
|
|
121
121
|
|
|
122
122
|
**Frequency**: When explicitly called with `/context-doctor` or auto-invoked at session start when MEMORY.md is detected at 180+ lines.
|
|
123
123
|
|
|
@@ -259,7 +259,7 @@ context-doctor (token/context) · harness-doctor (structure) · sim-conductor (s
|
|
|
259
259
|
|---|---|
|
|
260
260
|
| Want to also check structure after resolving token waste | `/harness-doctor` |
|
|
261
261
|
| Want to validate prescription results from external user perspective | `/sim-conductor Area A` |
|
|
262
|
-
| SKILL.md diagnosed as over-loaded (> 300 lines, no SKILL_detail.md) | `/
|
|
262
|
+
| SKILL.md diagnosed as over-loaded (> 300 lines, no SKILL_detail.md) | `/salience-splitter` — governance-semantic split |
|
|
263
263
|
| All three skills mentioned simultaneously | Three-Doctor Loop circuit activated — diagnosis→prescription→re-diagnosis cycle
|
|
264
264
|
|
|
265
265
|
## Done When
|
|
@@ -278,4 +278,4 @@ context-doctor (token/context) · harness-doctor (structure) · sim-conductor (s
|
|
|
278
278
|
**→ Three-Doctor Loop chain (auto-propose after diagnosis):**
|
|
279
279
|
- Prescription modifies SKILL.md / rules / CLAUDE.md → **propose `/harness-doctor`** re-check after fix (structural integrity)
|
|
280
280
|
- Prescription addresses user-facing context (onboarding, README, install guides) → **propose `/sim-conductor Area A`** (external user impact validation)
|
|
281
|
-
- SKILL.md detected as over-loaded → **auto-propose `/
|
|
281
|
+
- SKILL.md detected as over-loaded → **auto-propose `/salience-splitter`**: `"I see [skill-name] SKILL.md is [N] lines with no SKILL_detail.md. Want me to run /salience-splitter to do a governance-semantic split?"`
|
|
@@ -73,11 +73,11 @@ wc -l memory/MEMORY.md 2>/dev/null
|
|
|
73
73
|
# memory/*.md files exceeding 30K
|
|
74
74
|
find memory -name "*.md" -size +30k 2>/dev/null | xargs wc -l | sort -rn | head -10
|
|
75
75
|
|
|
76
|
-
# SKILL.md files > 300 lines with no SKILL_detail.md (
|
|
76
|
+
# SKILL.md files > 300 lines with no SKILL_detail.md (salience-splitter candidates)
|
|
77
77
|
find plugins -name "SKILL.md" 2>/dev/null | while read f; do
|
|
78
78
|
lines=$(wc -l < "$f")
|
|
79
79
|
detail=$(dirname "$f")/SKILL_detail.md
|
|
80
|
-
[ "$lines" -gt 300 ] && [ ! -f "$detail" ] && echo "[
|
|
80
|
+
[ "$lines" -gt 300 ] && [ ! -f "$detail" ] && echo "[salience-splitter candidate] $f ($lines lines)"
|
|
81
81
|
done
|
|
82
82
|
```
|
|
83
83
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: goal-quench
|
|
3
3
|
description: >-
|
|
4
|
-
Wraps /goal with a tiered safety + orchestration ladder. core (default): a token budget gate (pre-run estimate), mid-run budget thresholds, and an automatic post-run quality verification via pipeline-conductor — closing /goal's two gaps (Haiku evaluates completion, pipeline-conductor evaluates correctness). pro: adds context-doctor token reduction and agent-composer goal decomposition. max: adds
|
|
4
|
+
Wraps /goal with a tiered safety + orchestration ladder. core (default): a token budget gate (pre-run estimate), mid-run budget thresholds, and an automatic post-run quality verification via pipeline-conductor — closing /goal's two gaps (Haiku evaluates completion, pipeline-conductor evaluates correctness). pro: adds context-doctor token reduction and agent-composer goal decomposition. max: adds internal-first capability-gap fill (LOCAL_SKILL_REGISTRY skill-bus scan → plugin-recommender external search → auto_project_mapping map/cluster) and cross-ecosystem-synergy-detection pre-validation. The Phase-1 budget verdict auto-recommends the mode. Triggered by "goal with quality gate", "safe goal", "goal-quench", "orchestrate this goal", or before running /goal on high-stakes tasks.
|
|
5
5
|
user-invocable: true
|
|
6
6
|
allowed-tools: ["Read", "Write", "Bash", "Grep"]
|
|
7
7
|
model: sonnet
|
|
@@ -39,7 +39,7 @@ goal-quench is a ladder, not a fixed shape. The default (**core**) is the narrow
|
|
|
39
39
|
|---|---|---|---|
|
|
40
40
|
| **core** (default) | budget gate + mid-run thresholds + post-run quality gate | token-budget-gate, pipeline-conductor --quick | budget GREEN / YELLOW |
|
|
41
41
|
| **pro** | token-reduction pre-pass + goal decomposition into Waves | + context-doctor, agent-composer | budget ORANGE |
|
|
42
|
-
| **max** | capability-gap fill + synergy pre-validation
|
|
42
|
+
| **max** | **internal-first** capability-gap fill (skill-bus scan → external → map/cluster) + synergy pre-validation | + LOCAL_SKILL_REGISTRY scan, plugin-recommender, cross-ecosystem-synergy-detection, auto_project_mapping | budget RED |
|
|
43
43
|
|
|
44
44
|
Each mode is a **superset** of the one before it — pro does everything core does, plus more. Nothing in core is removed by escalating.
|
|
45
45
|
|
|
@@ -105,6 +105,7 @@ The clean-streak graduation above governs **unattended-no-review** operation (ru
|
|
|
105
105
|
- "goal-quench", before any long /goal session
|
|
106
106
|
- `/goal-quench --pro`, `/goal-quench --max`, "orchestrate this goal", "decompose this goal", "optimize then run this goal"
|
|
107
107
|
- "this goal is too big for one run", "find a tool for this goal if FH lacks one" (→ max mode)
|
|
108
|
+
- "assemble capabilities for this project", "develop project X with everything FH has", "what can FH + tools do for this project", "use all of FH's and others' sharp parts on this" (→ max mode, **project-dev capability-assembly** entry — internal skill-bus scan first, then external gap-fill, then map+cluster; token-efficient, non-expert-friendly)
|
|
108
109
|
- Automatically proposed when user mentions `/goal` on tasks estimated > 15K tokens
|
|
109
110
|
- Mode is auto-recommended by the Phase-1 budget verdict (GREEN/YELLOW → core, ORANGE → pro, RED → max)
|
|
110
111
|
|
|
@@ -190,14 +191,16 @@ goal-quench does **not** re-implement agent-composer's gates — its destructive
|
|
|
190
191
|
|
|
191
192
|
> **Detail**: See `SKILL_detail.md §Queue-Format` — queue file format, plan-ready output text, sidecar `.active` fields — read when writing the queue (Step B) or the sidecar fields (Step D).
|
|
192
193
|
|
|
193
|
-
### Step C —
|
|
194
|
+
### Step C — capability fill: internal-first, then external · max only
|
|
194
195
|
|
|
195
|
-
Triggered only when agent-composer Step 0.2 reports a capability **GAP** (`fit_score < 0.5` on a required-weight sub-task):
|
|
196
|
-
1. `plugin-recommender` searches FH + Codex + Claude Code marketplaces for a fitting skill/agent.
|
|
197
|
-
2. For each candidate, `cross-ecosystem-synergy-detection` pre-validates fit + overlap **before anything is installed**.
|
|
198
|
-
3. User decides: install / skip / general-purpose fallback (agent-composer's degraded-composition rule applies — `⚠️ degraded: [role]`).
|
|
196
|
+
Triggered only when agent-composer Step 0.2 reports a capability **GAP** (`fit_score < 0.5` on a required-weight sub-task). Fill order is **internal before external** — honors no-reinvention (use FH's + sibling projects' sharp parts before installing anything), and cheaper **on an internal hit** (a local registry read ≪ an external marketplace search; on an internal *miss* the scan is added overhead before the same external path):
|
|
199
197
|
|
|
200
|
-
|
|
198
|
+
1. **Internal scan first.** Run the `LOCAL_SKILL_REGISTRY` scan / Cross-Project Skill Bus (the runtime-root-derived scan under `.claude/registry/`) to check whether an existing **FH meta-skill or a sibling-project skill** already fills the gap. **Trust-gated dispatch** (the fields the registry carries are *consumed*, not just surfaced): an **FH meta-skill** hit → propose directly (Agent + Context Card, no install, token-cheap); a **non-FH sibling** hit → if `trust≠trusted` OR `writes≠read-only` → **ask-tier HITL before dispatch** (never propose-directly — sibling code is an injection surface), else propose. **Degrade direction**: if `.claude/registry/` is missing/malformed, treat as an internal-miss and **fall through to external (step 2), warn** — never silently skip capability fill (that drops the GAP sub-task unnoticed; capability-fill is a reversible surface → advisory-degrade per the Surface-Class Degrade Invariant).
|
|
199
|
+
2. **External only if internal has nothing.** `plugin-recommender` searches FH + Codex + Claude Code marketplaces + external repos for a fitting skill/agent; `cross-ecosystem-synergy-detection` pre-validates fit + overlap **before anything is installed**.
|
|
200
|
+
3. User decides: use-internal / install-external / skip / general-purpose fallback (agent-composer's degraded-composition rule applies — `⚠️ degraded: [role]`).
|
|
201
|
+
4. **Approved external capability → map + cluster (deferred to session close).** An adopted external skill or a newly-relevant sibling project is registered via `auto_project_mapping` — but that write **edits CLAUDE.md's track-mapping table and creates `tracks/{project}/` (an FH-asset change that trips the 4-axis auto-gate and shifts the onboarding is-mapped signal — [[feedback_tracks_dir_is_mapped_signal]])**, so it is **deferred to session close**, not run mid-`/goal`-loop: it passes the 4-axis gate as its own change instead of interrupting the run. The **next** run then discovers the capability internally at step 1 — the loop compounds.
|
|
202
|
+
|
|
203
|
+
max mode never installs or maps anything silently — internal hit, external discovery, synergy-check, and mapping are all surfaced for approval first.
|
|
201
204
|
|
|
202
205
|
### Step D — scope-driven sidecar configuration · pro + max
|
|
203
206
|
|
|
@@ -308,8 +311,10 @@ After each goal-quench run, append a calibration entry to `tracks/_meta/goal_que
|
|
|
308
311
|
- `token-budget-gate` — Phase 1 cost estimation (all modes)
|
|
309
312
|
- `context-doctor` — Phase 1.5 Step A token-reduction pre-pass (pro + max)
|
|
310
313
|
- `agent-composer` — Phase 1.5 Step B goal decomposition into Waves (pro + max)
|
|
311
|
-
- `
|
|
314
|
+
- `LOCAL_SKILL_REGISTRY` scan / Cross-Project Skill Bus — Phase 1.5 Step C internal-first scan (max only, GAP-triggered, before external)
|
|
315
|
+
- `plugin-recommender` — Phase 1.5 Step C external capability-gap fill (max only, GAP-triggered, only if no internal hit)
|
|
312
316
|
- `cross-ecosystem-synergy-detection` — Phase 1.5 Step C pre-validation of discovered candidates (max only)
|
|
317
|
+
- `auto_project_mapping` — Phase 1.5 Step C map/cluster of an adopted external capability (max only, approval-gated, deferred to session close)
|
|
313
318
|
- `pipeline-conductor` — Phase 3 quality gate (`--quick` for core/pro, `--full` for max; called by Stop hook)
|
|
314
319
|
- `field-harvest` — capture calibration data as reusable pattern after 10 runs
|
|
315
320
|
|
|
@@ -321,7 +326,9 @@ After each goal-quench run, append a calibration entry to `tracks/_meta/goal_que
|
|
|
321
326
|
Phase 1: token-budget-gate verdict output + mode resolved (core default, or pro/max via budget verdict / explicit flag)
|
|
322
327
|
+ .claude/goal-quench.active written (with mode: field) + thresholds injected
|
|
323
328
|
+ If pro/max: Phase 1.5 ran — context-doctor pre-pass + agent-composer plan;
|
|
324
|
-
max additionally: GAP-triggered
|
|
329
|
+
max additionally: GAP-triggered internal LOCAL_SKILL_REGISTRY scan FIRST (trust-gated dispatch);
|
|
330
|
+
plugin-recommender + cross-ecosystem-synergy pre-validation ONLY if no internal hit;
|
|
331
|
+
auto_project_mapping map/cluster deferred to session close only if an external capability was adopted (each surfaced for approval)
|
|
325
332
|
+ Phase 3 (on next response after /goal): .pending file detected + pipeline-conductor run
|
|
326
333
|
(--quick for core/pro, --full for max)
|
|
327
334
|
+ Verification verdict output (CLEAN/PENDING/BLOCKED/ESCALATE)
|
|
@@ -76,7 +76,7 @@ confirms the gap*, never a verdict the report emits on its own; surface each gap
|
|
|
76
76
|
| CLAUDE.md 100~200 lines | S-tier warning |
|
|
77
77
|
| CLAUDE.md 200+ lines | M-tier — separation or reduction needed |
|
|
78
78
|
| 15+ `##` sections in CLAUDE.md | S-tier warning |
|
|
79
|
-
| SKILL.md > 300 lines AND no `SKILL_detail.md` | S-tier — propose `/
|
|
79
|
+
| SKILL.md > 300 lines AND no `SKILL_detail.md` | S-tier — propose `/salience-splitter` (governance-semantic split, not compression) |
|
|
80
80
|
| Rules files unreferenced in CLAUDE.md | R-tier |
|
|
81
81
|
| weekly_audit 14~30 days elapsed | S-tier |
|
|
82
82
|
| weekly_audit 30+ days elapsed | M-tier |
|
|
@@ -318,7 +318,7 @@ Verdict: PASS (M-tier 0, "Structure healthy") | CONDITIONAL_PASS (S/R remain, no
|
|
|
318
318
|
**Three-Doctor Loop chain** (auto-propose after prescription report):
|
|
319
319
|
- M-tier + context/token waste → propose `/context-doctor`
|
|
320
320
|
- M-tier + user-facing behavior changes → propose `/sim-conductor Area A`
|
|
321
|
-
- SKILL.md S-tier (> 300 lines, no SKILL_detail.md) → auto-propose `/
|
|
321
|
+
- SKILL.md S-tier (> 300 lines, no SKILL_detail.md) → auto-propose `/salience-splitter`: `"I see [skill] SKILL.md is [N] lines with no SKILL_detail.md. Want me to run /salience-splitter?"`
|
|
322
322
|
- Both → propose full Three-Doctor Loop: context-doctor → sim-conductor Area A
|
|
323
323
|
|
|
324
324
|
---
|
|
@@ -137,7 +137,7 @@ FAIL routing: First FAIL → 1 re-synthesis allowed. FAIL after re-synthesis →
|
|
|
137
137
|
|
|
138
138
|
### Step 6 — Curator Lifecycle Review
|
|
139
139
|
|
|
140
|
-
**6-1 SKILL.md Lifecycle**: 30+ day unused → [STALE] candidate. `pinned: true` → never touch. ≥70% overlap → merge candidate suggestion. **> 300 lines AND no `SKILL_detail.md`** → propose `/
|
|
140
|
+
**6-1 SKILL.md Lifecycle**: 30+ day unused → [STALE] candidate. `pinned: true` → never touch. ≥70% overlap → merge candidate suggestion. **> 300 lines AND no `SKILL_detail.md`** → propose `/salience-splitter` (governance-semantic split — not compression; the grew-through-harvest pattern is a natural split trigger).
|
|
141
141
|
|
|
142
142
|
**6-1-a Archive-candidate auto-tag**: When 0 invocations in 30 days detected (cross-check `tracks/_meta/skill_usage.md`), auto-append `#archive-candidate` tag to that skill's CATALOG.md entry. No file deletion — tag only. User reviews tagged entries at next session start.
|
|
143
143
|
|
|
@@ -139,7 +139,9 @@ Y (add integration plan items to Step 1) / N (add-only, keep existing rules) / S
|
|
|
139
139
|
|
|
140
140
|
**[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.
|
|
141
141
|
|
|
142
|
-
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).
|
|
142
|
+
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) · **`env-delta SessionStart hook`** (Mode D — `scripts/fh_env_delta_scan.sh` registered in SessionStart; MISS if absent when the hub has sibling repos) · **`capability-escalation consent`** (per `[[capability_escalation_consent]]` — negotiate BOTH axes at onboarding so no later escalation is a surprise: *"Allow cross-family sidecars (external billing) for load-bearing verification?"* → `sidecar_consent`, and *"Allow Sonnet→Opus floor-up on depth-heavy turns (~3–5× cost)? Decline = stay at the Sonnet floor, asked per-occasion instead."* → `floorup_consent`; record both to the UAP. MISS if the UAP lacks either field — a skipped user is asked-once at first need, never sprung).
|
|
143
|
+
|
|
144
|
+
**env-delta detection (Mode D — the mechanical floor for claim ② auto-trigger)**: FH's "undeployed-asset discovery + auto-mapping" (CLAUDE.md claim ②) previously fired **only on explicit invocation** — a new sibling repo pulled, or a task-first session in an unmapped project, was **not** self-detected (the onboarding menu is suppressed on task-first entry by the metadata-is-not-intent / task-first guards, which are load-bearing and must stay). The `scripts/fh_env_delta_scan.sh` SessionStart hook (sibling of `fh_session_load.sh`) closes this **mechanically**: it scans the projects root for git repos that are neither mapped (`tracks/{name}/`) nor wizard-done nor skip-sentineled, and emits a **one-line PROPOSAL** into turn-0 context, firing regardless of task-first entry. It **proposes only** — mapping/install stays HITL; a skipped repo is recorded via a `{name}_mapping_skipped` sentinel so it never re-nags. This is the mechanical anchor over the prose/salience layer (three-family audit 2026-07-06 rated ② PARTIAL/THEATER precisely because the auto-trigger lived only in prose).
|
|
143
145
|
|
|
144
146
|
**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.
|
|
145
147
|
|
|
@@ -103,38 +103,16 @@ literal private token.
|
|
|
103
103
|
|
|
104
104
|
## Step 3. Scan
|
|
105
105
|
|
|
106
|
-
For each pattern in Step 1, grep the tracked set, then drop allowlisted hits.
|
|
107
|
-
|
|
108
|
-
```bash
|
|
109
|
-
cd "$REPO_PATH" || exit 1
|
|
110
|
-
# Build the tracked-file list once.
|
|
111
|
-
git ls-files > /tmp/_psa_tracked.txt
|
|
112
|
-
|
|
113
|
-
# Load your real patterns from the gitignored source (one "severity<TAB>regex" per line).
|
|
114
|
-
PATTERN_SRC="${PSA_PATTERNS:-.claude/rules/.public-surface-patterns}"
|
|
115
|
-
# Absent file ≠ CLEAN. An absent file is unconfigured (silent-failure risk); an EMPTY file is an
|
|
116
|
-
# explicit "no tokens to protect" → CLEAN. Distinguish the two.
|
|
117
|
-
[ -e "$PATTERN_SRC" ] || { echo "⚪ NOT CONFIGURED: no pattern source at $PATTERN_SRC. Create it (empty = explicit CLEAN) before trusting any verdict. Not scanning."; exit 2; }
|
|
118
|
-
|
|
119
|
-
# One grep pass per pattern row; the regex comes from the file, never hardcoded here.
|
|
120
|
-
while IFS=$'\t' read -r severity regex; do
|
|
121
|
-
[ -z "$regex" ] && continue
|
|
122
|
-
grep -nIE "$regex" $(cat /tmp/_psa_tracked.txt) 2>/dev/null | sed "s/^/[$severity] /"
|
|
123
|
-
done < "$PATTERN_SRC"
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
For each pattern, run `grep -nIE "<regex>" $(git ls-files)`:
|
|
127
|
-
- `-n` → line numbers (required for `file:line` output)
|
|
128
|
-
- `-I` → skip binary files
|
|
129
|
-
- `-E` → extended regex (alternation in the pattern table)
|
|
130
|
-
|
|
131
|
-
Then remove any hit whose `file` + matched `token` is on the Step 2 allowlist. Do this for **every**
|
|
106
|
+
For each pattern in Step 1, grep the tracked set, then drop allowlisted hits. Do this for **every**
|
|
132
107
|
pattern row before producing the report — do not stop at the first HIT.
|
|
133
108
|
|
|
134
|
-
**Binary / generated carve-out**:
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
109
|
+
**Binary / generated carve-out**: skip binaries. Additionally note (do not auto-suppress) hits inside
|
|
110
|
+
generated artifacts (e.g. `paper/*.html` exported from a private source) — these are real leaks on the
|
|
111
|
+
public surface and must be reported, but the fix is "regenerate from a sanitized source," not "edit the
|
|
112
|
+
HTML by hand." Flag them with a `(generated artifact)` note.
|
|
113
|
+
|
|
114
|
+
> **Detail**: See `SKILL_detail.md §Step3-Scan-Script` — the grep-per-pattern bash implementation,
|
|
115
|
+
> flag reference (`-n`/`-I`/`-E`) — read when executing this step.
|
|
138
116
|
|
|
139
117
|
---
|
|
140
118
|
|
|
@@ -151,23 +129,13 @@ reports):
|
|
|
151
129
|
`changeme`, `REDACTED`, `xxxx`, AWS-doc keys like `AKIAIOSFODNN7EXAMPLE`). A high-entropy *example* is
|
|
152
130
|
not a secret.
|
|
153
131
|
|
|
154
|
-
```bash
|
|
155
|
-
# FP-hygiene tests the MATCHED TOKEN only — never the whole line. A line-level `grep -v` would
|
|
156
|
-
# suppress a real leak that merely *mentions* an example (e.g. `user=<realname> # see EXAMPLE.md`),
|
|
157
|
-
# violating PSA's "allowlist tight" rule. So extract the matched span per hit and drop it only when
|
|
158
|
-
# the span is *entirely* a placeholder/example (anchored ^…$).
|
|
159
|
-
PLACEHOLDER='^(<[a-z0-9_-]+>|\{project\}|EXAMPLE|dummy|changeme|REDACTED|xxxx)$'
|
|
160
|
-
grep -nIE "$regex" $(cat /tmp/_psa_tracked.txt) 2>/dev/null | while IFS= read -r hit; do
|
|
161
|
-
tok=$(printf '%s' "$hit" | grep -oiE "$regex" | head -1)
|
|
162
|
-
printf '%s' "$tok" | grep -qiE "$PLACEHOLDER" && continue # token IS a placeholder → drop
|
|
163
|
-
printf '%s\n' "$hit"
|
|
164
|
-
done
|
|
165
|
-
```
|
|
166
|
-
|
|
167
132
|
This differs from the Step 2 allowlist: Step 2 suppresses by **file::token legitimacy**, Step 3b by
|
|
168
133
|
**token value-shape**. Both run — Step 2 then Step 3b. Keep it tight (PSA's "allowlist tight" rule): if a
|
|
169
134
|
token only *contains* an example substring but is otherwise a real private value, it still reports.
|
|
170
135
|
|
|
136
|
+
> **Detail**: See `SKILL_detail.md §Step3b-FP-Hygiene-Script` — the token-shape-only extraction bash
|
|
137
|
+
> implementation (never line-level) — read when executing this step.
|
|
138
|
+
|
|
171
139
|
---
|
|
172
140
|
|
|
173
141
|
## Step 3c. Ignore-Verification — the gitignore-mistake safeguard (root-cause, runs before Step 4)
|
|
@@ -178,39 +146,14 @@ tracked leak. For each expected-private path, `git check-ignore -v` reports whet
|
|
|
178
146
|
by which layer** (committed `.gitignore` · local `.git/info/exclude` · global `core.excludesFile`). A
|
|
179
147
|
path that resolves to no ignore rule is a MISS — surface it before it is ever `git add`ed.
|
|
180
148
|
|
|
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
149
|
- **OK** — ignored; the report names which layer covers it (operator-private files should resolve to
|
|
209
150
|
`.git/info/exclude` or `.gitignore`, never end up tracked).
|
|
210
151
|
- **MISS** — exists but no ignore rule covers it → counts as **🟠 MED** in the Step 4 verdict (a latent
|
|
211
152
|
leak, not yet a breach).
|
|
212
153
|
- **TRACKED** — already committed: Step 3 scans its *contents*; this also flags it for un-tracking if it
|
|
213
|
-
was meant to be private.
|
|
154
|
+
was meant to be private. Tracked status is tested **before** ignore status — a file can match an
|
|
155
|
+
ignore rule yet still be force-added (`git add -f`), the exact ignored-but-committed mechanism behind
|
|
156
|
+
the PR #109 leak, so TRACKED must win over a false-clean OK.
|
|
214
157
|
|
|
215
158
|
Why this is the safeguard for **gitignore mistakes** (a wrong assumption about what is ignored):
|
|
216
159
|
`.gitignore` is committed/shared, `.git/info/exclude` is local/personal, and a global `core.excludesFile`
|
|
@@ -218,6 +161,10 @@ ignores across all repos — `git check-ignore -v` is the one command that says
|
|
|
218
161
|
applies, so an "I thought it was ignored" error surfaces here instead of in a public PR (the PR #109
|
|
219
162
|
class of leak). Diagnostic-only: this step never writes — it reports, the operator adds the ignore rule.
|
|
220
163
|
|
|
164
|
+
> **Detail**: See `SKILL_detail.md §Step3c-Ignore-Verification-Script` — the expected-private-path
|
|
165
|
+
> enumeration + `git check-ignore`/`git ls-files --error-unmatch` bash implementation, bash/zsh
|
|
166
|
+
> portability note — read when executing this step.
|
|
167
|
+
|
|
221
168
|
---
|
|
222
169
|
|
|
223
170
|
## Step 4. Report
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: public-surface-audit-detail
|
|
3
|
+
description: On-demand execution detail for public-surface-audit — scan scripts, report/JSON templates, provenance.
|
|
4
|
+
load: on-demand
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## §Step3-Scan-Script
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
cd "$REPO_PATH" || exit 1
|
|
11
|
+
# Build the tracked-file list once.
|
|
12
|
+
git ls-files > /tmp/_psa_tracked.txt
|
|
13
|
+
|
|
14
|
+
# Load your real patterns from the gitignored source (one "severity<TAB>regex" per line).
|
|
15
|
+
PATTERN_SRC="${PSA_PATTERNS:-.claude/rules/.public-surface-patterns}"
|
|
16
|
+
# Absent file ≠ CLEAN. An absent file is unconfigured (silent-failure risk); an EMPTY file is an
|
|
17
|
+
# explicit "no tokens to protect" → CLEAN. Distinguish the two.
|
|
18
|
+
[ -e "$PATTERN_SRC" ] || { echo "⚪ NOT CONFIGURED: no pattern source at $PATTERN_SRC. Create it (empty = explicit CLEAN) before trusting any verdict. Not scanning."; exit 2; }
|
|
19
|
+
|
|
20
|
+
# One grep pass per pattern row; the regex comes from the file, never hardcoded here.
|
|
21
|
+
while IFS=$'\t' read -r severity regex; do
|
|
22
|
+
[ -z "$regex" ] && continue
|
|
23
|
+
grep -nIE "$regex" $(cat /tmp/_psa_tracked.txt) 2>/dev/null | sed "s/^/[$severity] /"
|
|
24
|
+
done < "$PATTERN_SRC"
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
For each pattern, run `grep -nIE "<regex>" $(git ls-files)`:
|
|
28
|
+
- `-n` → line numbers (required for `file:line` output)
|
|
29
|
+
- `-I` → skip binary files
|
|
30
|
+
- `-E` → extended regex (alternation in the pattern table)
|
|
31
|
+
|
|
32
|
+
Then remove any hit whose `file` + matched `token` is on the Step 2 allowlist. Do this for **every**
|
|
33
|
+
pattern row before producing the report — do not stop at the first HIT.
|
|
34
|
+
|
|
35
|
+
**Binary / generated carve-out**: `-I` already skips binaries. Additionally note (do not auto-suppress)
|
|
36
|
+
hits inside generated artifacts (e.g. `paper/*.html` exported from a private source) — these are real
|
|
37
|
+
leaks on the public surface and must be reported, but the fix is "regenerate from a sanitized source",
|
|
38
|
+
not "edit the HTML by hand". Flag them with a `(generated artifact)` note.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## §Step3b-FP-Hygiene-Script
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
# FP-hygiene tests the MATCHED TOKEN only — never the whole line. A line-level `grep -v` would
|
|
46
|
+
# suppress a real leak that merely *mentions* an example (e.g. `user=<realname> # see EXAMPLE.md`),
|
|
47
|
+
# violating PSA's "allowlist tight" rule. So extract the matched span per hit and drop it only when
|
|
48
|
+
# the span is *entirely* a placeholder/example (anchored ^…$).
|
|
49
|
+
PLACEHOLDER='^(<[a-z0-9_-]+>|\{project\}|EXAMPLE|dummy|changeme|REDACTED|xxxx)$'
|
|
50
|
+
grep -nIE "$regex" $(cat /tmp/_psa_tracked.txt) 2>/dev/null | while IFS= read -r hit; do
|
|
51
|
+
tok=$(printf '%s' "$hit" | grep -oiE "$regex" | head -1)
|
|
52
|
+
printf '%s' "$tok" | grep -qiE "$PLACEHOLDER" && continue # token IS a placeholder → drop
|
|
53
|
+
printf '%s\n' "$hit"
|
|
54
|
+
done
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
This differs from the Step 2 allowlist: Step 2 suppresses by **file::token legitimacy**, Step 3b by
|
|
58
|
+
**token value-shape**. Both run — Step 2 then Step 3b. Keep it tight (PSA's "allowlist tight" rule): if a
|
|
59
|
+
token only *contains* an example substring but is otherwise a real private value, it still reports.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## §Step3c-Ignore-Verification-Script
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
# Expected-private set = conventional FH local-only files, EXTENDED with any `# private-path: <path>`
|
|
67
|
+
# lines the operator added to the gitignored pattern source (self-extends per repo — not a frozen
|
|
68
|
+
# operator snapshot). Built one-path-per-line + while-read so it is portable across bash AND zsh
|
|
69
|
+
# (zsh does not word-split an unquoted variable, so `for f in $VAR` would break). A non-existent file
|
|
70
|
+
# is skipped; an all-absent set emits n/a, never a silent pass.
|
|
71
|
+
present=$({ printf '%s\n' CLAUDE.local.md .claude/rules/.public-surface-patterns \
|
|
72
|
+
.claude/rules/local_fh_context.md tracks/_meta/user_adaptation_profile.md
|
|
73
|
+
grep -E '^# private-path:' .claude/rules/.public-surface-patterns 2>/dev/null \
|
|
74
|
+
| sed -E 's/^# private-path:[[:space:]]*//'; } \
|
|
75
|
+
| awk 'NF' | sort -u | while IFS= read -r f; do [ -e "$f" ] && printf '%s\n' "$f"; done)
|
|
76
|
+
[ -z "$present" ] && echo "n/a (no expected-private files present in this repo — add '# private-path:' lines to the pattern source if any exist)"
|
|
77
|
+
printf '%s\n' "$present" | while IFS= read -r f; do
|
|
78
|
+
[ -z "$f" ] && continue
|
|
79
|
+
# Tracked status is tested FIRST: a file can match an ignore rule yet still be force-added
|
|
80
|
+
# (`git add -f`) — the exact ignored-but-committed mechanism behind the PR #109 leak. Tracked wins,
|
|
81
|
+
# so an ignored-but-committed file reports TRACKED (not a false-clean OK).
|
|
82
|
+
if git ls-files --error-unmatch "$f" >/dev/null 2>&1; then
|
|
83
|
+
echo "TRACKED $f (already committed — Step 3 scans its contents; un-track if it must be private: git rm --cached)"
|
|
84
|
+
elif rule=$(git check-ignore -v "$f" 2>/dev/null); then
|
|
85
|
+
echo "OK $f → ignored by [$rule]"
|
|
86
|
+
else
|
|
87
|
+
echo "MISS $f (exists, NOT ignored, NOT tracked — one 'git add .' from a leak; add an ignore rule)"
|
|
88
|
+
fi
|
|
89
|
+
done
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Why this is the safeguard for **gitignore mistakes** (a wrong assumption about what is ignored):
|
|
93
|
+
`.gitignore` is committed/shared, `.git/info/exclude` is local/personal, and a global `core.excludesFile`
|
|
94
|
+
ignores across all repos — `git check-ignore -v` is the one command that says *which* rule (if any)
|
|
95
|
+
applies, so an "I thought it was ignored" error surfaces here instead of in a public PR (the PR #109
|
|
96
|
+
class of leak). Diagnostic-only: this step never writes — it reports, the operator adds the ignore rule.
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## §Report-Template
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
public-surface-audit — Operator-Private Token Scan
|
|
104
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
105
|
+
Target: {REPO_PATH} | Tracked files scanned: {N}
|
|
106
|
+
|
|
107
|
+
🔴 HIGH ({count})
|
|
108
|
+
{file}:{line} → {matched token} [class: username | company asset]
|
|
109
|
+
🟠 MED ({count})
|
|
110
|
+
{file}:{line} → {matched token} [class: absolute home path | ignore-MISS (Step 3c)]
|
|
111
|
+
🟡 LOW ({count})
|
|
112
|
+
{file}:{line} → {matched token} [class: companion-store | private wiring]
|
|
113
|
+
|
|
114
|
+
Allowlist-suppressed: {count} hit(s) (legitimate references — not leaks)
|
|
115
|
+
|
|
116
|
+
Verdict:
|
|
117
|
+
⚪ NOT CONFIGURED — pattern source absent (nothing scanned — NOT a clean result; set up first)
|
|
118
|
+
🟢 CLEAN — pattern source present (incl. empty), 0 HIGH + 0 MED + 0 LOW (after allowlist)
|
|
119
|
+
🟡 REVIEW — 0 HIGH + 0 MED, LOW-only (drift, not a breach)
|
|
120
|
+
🔴 LEAK — 1+ HIGH or 1+ MED (block publish / fix before commit)
|
|
121
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## §JSON-Schema
|
|
127
|
+
|
|
128
|
+
```json
|
|
129
|
+
{
|
|
130
|
+
"target": "{REPO_PATH}",
|
|
131
|
+
"tracked_files": 0,
|
|
132
|
+
"findings": [
|
|
133
|
+
{"file": "path", "line": 42, "token": "<matched>", "severity": "HIGH", "class": "username"}
|
|
134
|
+
],
|
|
135
|
+
"counts": {"HIGH": 0, "MED": 0, "LOW": 0, "suppressed": 0},
|
|
136
|
+
"verdict": "CLEAN"
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## §Sister-Asset-Provenance
|
|
143
|
+
|
|
144
|
+
Step 3b (FP hygiene) and Step 5 (`--json`) were imported from **garrytan/gstack** `gstack-redact`
|
|
145
|
+
(`lib/redact-engine.ts`) during a hands-on sister-asset cross-audit (2026-06-06; see
|
|
146
|
+
`tracks/_audit/session_2026_06_06_gstack_sister_handson.md`). They are adapted to PSA's operator-IP
|
|
147
|
+
ontology — `gstack-redact`'s generic secret/PII classes (AWS / PEM / JWT / hostname) stay out of PSA's
|
|
148
|
+
scope (orthogonal coverage: PSA = operator-IP leak, redact = generic secret). The reverse direction
|
|
149
|
+
(PSA's operator private-codename + bare-username classes, which `gstack-redact` structurally cannot
|
|
150
|
+
detect) is a candidate contribution back to gstack.
|
|
@@ -1,15 +1,25 @@
|
|
|
1
1
|
---
|
|
2
|
-
name:
|
|
3
|
-
description: Splits an over-loaded SKILL.md into always-loaded
|
|
2
|
+
name: salience-splitter
|
|
3
|
+
description: Splits an over-loaded always-loaded context asset — a SKILL.md, CLAUDE.md, or memory index — into a lean always-loaded layer + an on-demand layer, using a governance-semantic criterion (not length, but when the content is needed), connected by imperative pointers. Based on paper §9.5 Protocol-Priority Split pattern. Diagnoses, classifies, splits, and verifies in one pass. Renamed from skill-splitter (old name still routes here).
|
|
4
4
|
user-invocable: true
|
|
5
5
|
allowed-tools: ["Read", "Write", "Edit", "Bash", "Grep", "Glob"]
|
|
6
6
|
model: sonnet
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
-
#
|
|
9
|
+
# salience-splitter — Governance-Semantic Context Split
|
|
10
10
|
|
|
11
|
-
>
|
|
12
|
-
>
|
|
11
|
+
> **Renamed from `skill-splitter` (2026-07-05).** Old-name references still route here. The rename reflects
|
|
12
|
+
> the generalized scope: the split criterion applies to **any always-loaded context asset** — a SKILL.md,
|
|
13
|
+
> a CLAUDE.md, or a memory index — not only skills. The label now names the substance (salience-tiering of
|
|
14
|
+
> always-loaded context), not one instance of it. Dogfood: applied to a memory index 2026-07-05.
|
|
15
|
+
|
|
16
|
+
> An always-loaded asset that holds everything in one layer is not simple — it is unscoped.
|
|
17
|
+
> The goal is a lean always-loaded layer + an on-demand layer, not one file and its appendix.
|
|
18
|
+
|
|
19
|
+
**Scope (all three share one criterion — salience: what must be in attention every load):**
|
|
20
|
+
- **SKILL.md** → always-loaded SKILL.md + on-demand `SKILL_detail.md`
|
|
21
|
+
- **CLAUDE.md** → lean rules + on-demand detail docs (imperative `> **Detail**: See …` pointers)
|
|
22
|
+
- **memory index** → hot `MEMORY.md` + on-demand `MEMORY_archive.md` (cold/closed/superseded entries)
|
|
13
23
|
|
|
14
24
|
## Trigger Phrases
|
|
15
25
|
|
|
@@ -19,7 +29,7 @@ model: sonnet
|
|
|
19
29
|
| "context-doctor flagged this skill", "SKILL.md is bloated" | Post-diagnosis split |
|
|
20
30
|
| "I can't see the key parts", "too much detail in the skill file" | Readability problem |
|
|
21
31
|
| "separate the bash from the logic", "move the templates out" | Structural refactor request |
|
|
22
|
-
| `/
|
|
32
|
+
| `/salience-splitter` | Explicit invocation |
|
|
23
33
|
|
|
24
34
|
---
|
|
25
35
|
|
|
@@ -63,7 +73,7 @@ Step 4 — Verify
|
|
|
63
73
|
|
|
64
74
|
> **Detail**: See `SKILL_detail.md §Verification-Checklist` — pre-commit checklist table (8 checks) — read when running Step 4 verification.
|
|
65
75
|
|
|
66
|
-
> **Detail**: See `SKILL_detail.md §Split-Execution` — step-by-step trimming procedure, SKILL_detail.md front-matter format, orphan
|
|
76
|
+
> **Detail**: See `SKILL_detail.md §Split-Execution` — step-by-step trimming procedure, SKILL_detail.md front-matter format, orphan-section check — read when executing Steps 2–3.
|
|
67
77
|
|
|
68
78
|
> **Detail**: See `SKILL_detail.md §Classification` — ambiguous content decision algorithm, behavioral-vs-implementation test, 12 annotated examples — read when unsure which layer a section belongs to.
|
|
69
79
|
|
|
@@ -76,7 +86,7 @@ Pointers must be **imperative** (not advisory). The difference:
|
|
|
76
86
|
| Form | Risk |
|
|
77
87
|
|---|---|
|
|
78
88
|
| Advisory: `"see SKILL_detail.md for details"` | Consumer agent may skip |
|
|
79
|
-
| **Imperative**: `"> **Detail**: See \`SKILL_detail.md
|
|
89
|
+
| **Imperative**: `"> **Detail**: See \`SKILL_detail.md §<SectionName>\` — [what's there] — read when [specific condition]."` | Consumer agent loads on trigger |
|
|
80
90
|
|
|
81
91
|
Every removed section must have exactly one imperative pointer at the point of removal in SKILL.md.
|
|
82
92
|
|
|
@@ -113,7 +123,7 @@ Run on a SKILL.md when **any one** of:
|
|
|
113
123
|
```
|
|
114
124
|
Step 1 classification table produced
|
|
115
125
|
+ SKILL.md trimmed: triggers · principles · step overview · decision tables · Done When retained
|
|
116
|
-
+ SKILL.md has imperative pointer for every removed section (> **Detail**: See SKILL_detail.md
|
|
126
|
+
+ SKILL.md has imperative pointer for every removed section (> **Detail**: See SKILL_detail.md §<X>)
|
|
117
127
|
+ SKILL_detail.md created: ## §SectionName header for every pointer in SKILL.md
|
|
118
128
|
+ phantom-quench: 0 phantoms (all §pointers resolve)
|
|
119
129
|
→ Fallback (skill unavailable): run §Verification-Checklist manually from SKILL_detail.md
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
---
|
|
2
|
-
name:
|
|
3
|
-
description: Detail reference for
|
|
2
|
+
name: salience-splitter-detail
|
|
3
|
+
description: Detail reference for salience-splitter — content classification algorithm, pointer format variants, verification checklist. Load when executing a specific step.
|
|
4
4
|
load: on-demand
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
#
|
|
7
|
+
# salience-splitter — Detail Reference
|
|
8
8
|
|
|
9
9
|
> Load when executing a specific step. SKILL.md contains the core principle, step overview, pointer format requirement, and Done When.
|
|
10
10
|
|
|
@@ -70,13 +70,13 @@ Behavioral rules always pass this test (even if rarely triggered, the consumer n
|
|
|
70
70
|
### Standard pointer (single section reference)
|
|
71
71
|
|
|
72
72
|
```markdown
|
|
73
|
-
> **Detail**: See `SKILL_detail.md
|
|
73
|
+
> **Detail**: See `SKILL_detail.md §<SectionName>` — [one-line description of what's there] — read when [specific condition that triggers need].
|
|
74
74
|
```
|
|
75
75
|
|
|
76
76
|
### Multi-item pointer (several related sections)
|
|
77
77
|
|
|
78
78
|
```markdown
|
|
79
|
-
> **Detail**: See `SKILL_detail.md
|
|
79
|
+
> **Detail**: See `SKILL_detail.md §<SectionName-A>` (bash scripts) · `§<SectionName-B>` (format templates) — read when executing this step.
|
|
80
80
|
```
|
|
81
81
|
|
|
82
82
|
### Pointer placement rules
|
|
@@ -96,7 +96,7 @@ Advisory (risky — consumer may skip):
|
|
|
96
96
|
|
|
97
97
|
Imperative (required form):
|
|
98
98
|
```
|
|
99
|
-
"> **Detail**: See `SKILL_detail.md
|
|
99
|
+
"> **Detail**: See `SKILL_detail.md §<Step6-Detail>` — bash for STALE detection, memory scan, skill usage leaderboard — read when executing Step 6."
|
|
100
100
|
```
|
|
101
101
|
|
|
102
102
|
The imperative form includes:
|