@chrono-meta/fh-gate 2.0.1 → 2.2.0
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/rules/fh_4axis_gate.md +77 -1
- package/.claude-plugin/marketplace.json +3 -3
- package/AGENTS.md +26 -3
- package/CLAUDE.md +240 -4
- package/knowledge/shared/harness-core/capability_composition_contract.md +68 -0
- package/knowledge/shared/harness-core/fh_three_layer_canon.md +38 -12
- package/knowledge/shared/harness-core/field_verdict_crossfamily_gate.md +115 -3
- package/knowledge/shared/harness-core/harness_incubator_doctrine.md +82 -0
- package/knowledge/shared/harness-core/harness_terminal_correlation_and_recommendations.md +85 -10
- package/knowledge/shared/harness-core/ship_readiness_gate.md +241 -1
- package/knowledge/shared/learnings/subagent_invocations_log.yaml +102 -0
- package/knowledge/shared/rules/sister_asset_protocol.md +12 -0
- package/package.json +7 -2
- package/plugins/fh-commons/.claude-plugin/plugin.json +1 -1
- package/plugins/fh-commons/agents/quench-challenger.md +6 -1
- package/plugins/fh-commons/skills/ko-tech-writer/fixtures/known_negative.md +19 -0
- package/plugins/fh-commons/skills/ko-tech-writer/fixtures/known_positive.md +20 -0
- package/plugins/fh-meta/.claude-plugin/plugin.json +1 -1
- package/plugins/fh-meta/CHANGELOG.md +88 -0
- package/plugins/fh-meta/skills/auto-decorrelation/SKILL.md +14 -2
- package/plugins/fh-meta/skills/steel-quench/SKILL_detail.md +13 -0
- package/plugins/fh-meta/skills/verify-bidirectional/SKILL.md +34 -1
- package/scripts/capability_registry_check.sh +75 -12
- package/scripts/chamber_run.sh +39 -5
- package/scripts/chamber_witness.sh +25 -0
- package/scripts/fh-gate.sh +16 -1
- package/scripts/ko_tech_writer_calibrate.py +127 -0
- package/scripts/package_coverage_check.sh +10 -0
- package/scripts/prepublish_scope_note.sh +139 -0
- package/scripts/publish_freshness_check.sh +21 -2
- package/scripts/selfcheck.sh +32 -6
- package/scripts/test_fh_gate_regressions.sh +21 -9
- package/scripts/test_ko_tech_writer_lanes.sh +61 -0
- package/scripts/test_marker_axes_run_lanes.sh +87 -3
- package/scripts/test_marker_crossfamily_lanes.sh +31 -1
- package/templates/.git-hooks/pre-commit +225 -10
- package/templates/subagent-tally-hook.json +2 -2
|
@@ -67,7 +67,11 @@ No user request is needed — this is a mandatory autonomous step, not a proposa
|
|
|
67
67
|
FH asset modified → Axis 1 (templates/regression_guard.sh --pr {BRANCH})
|
|
68
68
|
→ Axis 2 (/steel-quench) → Axis 3 (/phantom-quench)
|
|
69
69
|
→ marker: tracks/_meta/.axes_23_passed_{branch}_{date}.marker
|
|
70
|
-
(required fields: axis2-engine / axis2-model / floor-status / axis2-evidence
|
|
70
|
+
(required fields: axis2-engine / axis2-model / floor-status / axis2-evidence /
|
|
71
|
+
**`axes-run:`** + **`controls:`** (see §Marker axis fields below — these were enforced by the
|
|
72
|
+
hook since 2026-08-10 and listed in NO rule file until 2026-08-17; the spec lived only in the
|
|
73
|
+
hook and in two CLAUDE.md/AGENTS.md one-liners, so an author reading the rules could not learn
|
|
74
|
+
the format that blocks their commit);
|
|
71
75
|
+ **`crossfamily:`** — required on LOAD-BEARING changes only, and TYPED since 2026-08-08:
|
|
72
76
|
`panel(<families>)` | `declined` | `DEGRADED_SINGLE_FAMILY` | `DEGRADED_PANEL_UNUSED` |
|
|
73
77
|
`UNKNOWN`, the three degrade values requiring substantive grounds on the same line.
|
|
@@ -126,6 +130,78 @@ no runnable path exists (run-first, ask-last — sonnet_floor_doctrine.md §Auto
|
|
|
126
130
|
|
|
127
131
|
Record sim results in the Axes 2–3 marker + sub-agent invocation log.
|
|
128
132
|
|
|
133
|
+
### Marker axis fields — `axes-run:` · `controls:` · `standpoint:`
|
|
134
|
+
|
|
135
|
+
These are enforced (the first two) or expected (the third) on the Axes 2–3 marker. Until 2026-08-17
|
|
136
|
+
**none of the three appeared in any rule file** — the format that hard-blocks the commit was legible
|
|
137
|
+
only from `templates/.git-hooks/pre-commit` itself. That is a gate-locality defect on the *spec*
|
|
138
|
+
side: the rule the author reads did not describe the check the author must pass.
|
|
139
|
+
|
|
140
|
+
**`axes-run:` — one line, all keys present, `none` for axes not run.** Silence is not zero: an axis
|
|
141
|
+
you skipped is written `none`, never omitted. Omitting it makes the reader parse an absence as a
|
|
142
|
+
decision.
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
# markers dated BEFORE 2026-08-17 — old 4-axis array, ASCII keys
|
|
146
|
+
axes-run: a=<다른 계열> b=<첫 실사용> c=<기록 그라운딩> d=<되돌림 실측>
|
|
147
|
+
|
|
148
|
+
# markers dated 2026-08-17 OR LATER — 6-axis array, circled keys
|
|
149
|
+
axes-run: ⓐ=<다른 계열> ⓑ=→standpoint ⓒ=<격리 그라운딩> ⓓ=<3자 대면> ⓔ=<첫 실사용> ⓕ=<되돌림 실측>
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
🟥 **The two arrays are not the same letters shifted — `b` and `d` mean different axes in each.**
|
|
153
|
+
Old `b`=첫 실사용 is now **ⓔ**; old `d`=되돌림 is now **ⓕ**. Copying an old line forward silently
|
|
154
|
+
swaps two axes, and no error fires.
|
|
155
|
+
|
|
156
|
+
**Which array a marker used is decided by the date in its filename** (`< 2026-08-17` = old 4-axis).
|
|
157
|
+
⚠️ **The notation is NOT the discriminator** — the first version of this section said it was
|
|
158
|
+
("circled keys = 6-axis, so an auditor can grep"), and a hand-count of the corpus refuted it: of 53
|
|
159
|
+
markers carrying `axes-run`, 4 use circled keys and 1 mixes, and **2 of those 4 are dated 2026-08-10
|
|
160
|
+
while meaning the OLD axes** (`ⓑ 첫실사용` · `ⓓ 되돌림` — ⓔ and ⓕ in the current array). The hook
|
|
161
|
+
never reads those markers so no commit is affected; the party that gets a wrong answer is the
|
|
162
|
+
**auditor**. Aligning the notation is still worth it going forward — it stops the next author from
|
|
163
|
+
copying an old line — but it does not work backwards.
|
|
164
|
+
|
|
165
|
+
⚠️ **The grace-date comparison is an unreachable branch in production, and saying so is the point.**
|
|
166
|
+
The call site builds the marker path from `${TODAY}`, so `mdate` is always today; no real commit
|
|
167
|
+
after 2026-08-17 takes the `six=0` path, and the only live consumer is the fixture suite. **What
|
|
168
|
+
protected the existing markers was the path construction, not the constant** — the same reason
|
|
169
|
+
`crossfamily:` could go from free prose to a closed enum eight days earlier with no cutoff at all.
|
|
170
|
+
|
|
171
|
+
- **ⓑ입장 carries a pointer, not a value** — `standpoint:` is its canonical field, so writing the
|
|
172
|
+
value in both places would be a double record. `ⓑ=→standpoint` requires a non-empty `standpoint:`
|
|
173
|
+
line to exist (a pointer at nothing is not a record). Enforced on any ⓑ value *referencing*
|
|
174
|
+
standpoint, arrow or not — requiring the arrow was fail-open and was measured as such.
|
|
175
|
+
- **Multiple `axes-run:` lines block.** Only the first is read, so a second line is not *rejected*,
|
|
176
|
+
it is **invisible** — anything written there bypasses the check entirely.
|
|
177
|
+
- **Grace dates are deliberate**: `AXES_RUN_GRACE_DATE=2026-08-10`, `SIX_AXES_GRACE_DATE=2026-08-17`,
|
|
178
|
+
compared against the date in the marker's **filename**, boundary `<` (the grace day itself is
|
|
179
|
+
required). Retroactive enforcement would block every in-flight branch, and that over-block trains
|
|
180
|
+
`--no-verify`, which disarms the Destructive-Op gate living in the same hook.
|
|
181
|
+
|
|
182
|
+
**`controls:` — the liveness of the controls, not their existence.** An axis is «run» only with an
|
|
183
|
+
execution output in which a control was alive; "붙였다" without a life/death token is vacuous and
|
|
184
|
+
blocks. Note the asymmetry this field exists for: *having* a control is not *having discrimination*
|
|
185
|
+
— a known-negative only tells you whether false positives exist at all.
|
|
186
|
+
|
|
187
|
+
```
|
|
188
|
+
controls: alive — known-positive 'X' 3 hits · known-negative 0
|
|
189
|
+
controls: n/a — no measurement in this delta (<reason>)
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
**`standpoint:`** — closed enum, canonical spec in
|
|
193
|
+
`knowledge/shared/harness-core/field_verdict_crossfamily_gate.md §7`. **Still validated by nothing**
|
|
194
|
+
— zero hook lines, no fixture suite. Recorded here so the gap is visible from the rules side rather
|
|
195
|
+
than only from the hook's absence.
|
|
196
|
+
|
|
197
|
+
**Scope, unchanged**: form + non-vacuity + auditability, **never provenance**. A marker claiming
|
|
198
|
+
`ⓐ=codex` when codex never ran passes — deliberately. Catching that is cross-family review *reading*
|
|
199
|
+
the marker, which is not this hook's job.
|
|
200
|
+
|
|
201
|
+
> Fixtures: `scripts/test_marker_axes_run_lanes.sh` (25 lanes, incl. wiring anchor + over-block
|
|
202
|
+
> controls). Extending the format means adding lanes there, and running the **revert probe** — a
|
|
203
|
+
> lane that stays green when you disable the branch it claims to anchor is decoration.
|
|
204
|
+
|
|
129
205
|
### Reviewer-visible evidence — the marker is not readable from the other side
|
|
130
206
|
|
|
131
207
|
**Rule**: a PR touching FH assets carries a **sanitized evidence capsule** in its body — what was
|
|
@@ -11,13 +11,13 @@
|
|
|
11
11
|
"plugins": [
|
|
12
12
|
{
|
|
13
13
|
"name": "fh-meta",
|
|
14
|
-
"version": "2.0
|
|
15
|
-
"description": "Hub meta-operations toolkit — 35 skills + 7 agents. New in 2.0.1: harness-doctor cadence hook, portability lint wired into pre-commit, branch_claim.sh claim-count-vs-tree-count warning, louder confidentiality-scan fail-open notice, fh-gate.sh missing-package.json survival, identity ① reclassified 🟢 (cross-harness adapters + relay argument channel). New in 1.4.53: `fh-codex-doctor` (npm bin) — Codex adapter drift scanner; reads the documented M1/M2/M3 skill tier map + skill/agent source and reports codex-native/adapter-required/claude-native/unclassified per unit, wired into `npm test`/`prepublishOnly` (fail-closed on unclassified Claude-native primitives). New in 1.4.49: steel-quench gains Step 0.6 Verdict-Invariance Probe (groundedness axis — a load-bearing judged gate's verdict must track behavior, not rubric phrasing; measured flip-count over cross-family paraphrases; arXiv:2605.06161 Policy Invariance anchor); multi_model_sidecar_strategy §Vendor-native harness (a model is strongest in its own vendor CLI — Claude/CC, GPT/codex, Gemini/Antigravity; a universal router degrades all of them, so it stays an autocomplete/QA sidecar, never orchestration); predelete_check.sh fail-closed rewrite; memory-hygiene A-TMA anchor. New in 1.4.48: phantom-quench + steel-quench gain external frontier anchors (arXiv:2607.02052 package-hallucination; arXiv:2607.02057 prompt-coverage-adequacy); README model-flat claim reframed from a per-release point-curve to structural invariants (operation flattens across tiers; depth tier-order fixed within a generation). New in 1.4.47: onboarding step ① surfaces the Mode D companion-store session-start load in the auto-read salience anchor (previously only in the local binding + rules, so a greeting could skip the load). New in 1.4.46: context-doctor command-output axis (route to rtk/proxy for verbose CLI stdout, complementing .claudeignore; risk-gated to token-scarce envs). New in 1.4.41: context-doctor 2026 trigger vocab (context engineering/rot/collapse) + phantom-citation hardening; hub measurement-integrity-checklist (cross-model measurement pre-flight: display-name pin/reps≥3/discriminating probe). New in 1.4.40: install-wizard queryable-wiki scaffold (INDEX + session-start read + R/W/C ingest). New in 1.4.39: auto-decorrelation (cross-family verifier sidecar recruitment) + video-ingest (capability-routed video ingestion). New in 1.4.x: verify-axis check-class taxonomy (mandatory-pass/measured/judged), no-reinvention Tier-0 inventory, 7-class failure taxonomy, Destructive-Op Gate, Wave-T (Temper), tier-floor governance, Mode D Model Notice, FC consent lane, default-Sonnet guidance. New in 1.3.0: public-surface-audit, field-harvest Mode B auto-trigger, 4-axis gate scope ext. Validated cross-CLI: Claude Code, Codex, Gemini.",
|
|
14
|
+
"version": "2.2.0",
|
|
15
|
+
"description": "New in 2.2.0: BREAKING (gate): chamber step 6 now reads ACTUAL.md, not BUDGET.md — an in-flight chamber run whose actual cost sits in BUDGET.md blocks until the ACTUAL: line moves to tracks/_chamber/<slug>/ACTUAL.md (the runner prints the path). Why: BUDGET.md's pre-verdict hash IS the ordering witness, and step 6 hard-blocked until that same file changed, so every run that reached COMPLETE necessarily mutated a witnessed artifact and verify returned TAMPERED — the chamber's promotion condition was unsatisfiable by construction, not by strictness. Two roles (immutable witness / post-verdict calibration sink) had collided in one file; each was correct alone, so neither side's code showed the conflict. Also: ko-tech-writer Step 2/4-b scans are now calibration-backed (known-pair fixtures + reproducible command, shipped) — discrimination is proven, 'zero residue' is explicitly NOT; chamber lane suite 12 -> 33 including the runner x witness seam no test covered; chamber_run.sh now teaches the two-commit discipline (gate hashes and verdict hash must land in separate commits/PRs — it previously advised the opposite). New in 2.1.0: BREAKING (gate): `crossfamily: declined` in an Axes 2-3 marker now requires grounds naming a record path that RESOLVES on disk — bare `declined`, and `declined` justified by author judgment, are blocked at commit. Remedy: cite where the operator decision lives (e.g. `.. — operator declined sidecars, per knowledge/shared/rules/operational_adaptation.md`), or use `DEGRADED_PANEL_UNUSED` if a panel was reachable and you chose not to recruit it — which is what author judgment actually is. `declined` was the only enum value with no grounds requirement; a cross-family review then broke the first (vocabulary-grep) fix three ways — self-validating on the value's own token, vacuous keyword passes, and over-blocking real declinations in natural prose — so the check asserts a resolvable record instead of words. Also: standpoint axis gains `tier1b` (a STATIC read of a target repo, executed nothing) plus a decide-in-order procedure, after blind floor-tier sims graded pure cold-reads as `tier2` three rounds running; steel-quench Wave 1's sixth angle (gate-locality) gains the output-template row it never had, so a mandatory angle stops being structurally unreportable; verify-bidirectional gains category 5 (prescriptive doctrine statement); Sister Asset Protocol gains an active-adoption trigger; new resident doctrine — Mechanization Boundary, Local Execution First, Skeleton-not-Muscle, Expedition track, and this package's versioning policy. Hub meta-operations toolkit — 35 skills + 7 agents. New in 2.0.1: harness-doctor cadence hook, portability lint wired into pre-commit, branch_claim.sh claim-count-vs-tree-count warning, louder confidentiality-scan fail-open notice, fh-gate.sh missing-package.json survival, identity ① reclassified 🟢 (cross-harness adapters + relay argument channel). New in 1.4.53: `fh-codex-doctor` (npm bin) — Codex adapter drift scanner; reads the documented M1/M2/M3 skill tier map + skill/agent source and reports codex-native/adapter-required/claude-native/unclassified per unit, wired into `npm test`/`prepublishOnly` (fail-closed on unclassified Claude-native primitives). New in 1.4.49: steel-quench gains Step 0.6 Verdict-Invariance Probe (groundedness axis — a load-bearing judged gate's verdict must track behavior, not rubric phrasing; measured flip-count over cross-family paraphrases; arXiv:2605.06161 Policy Invariance anchor); multi_model_sidecar_strategy §Vendor-native harness (a model is strongest in its own vendor CLI — Claude/CC, GPT/codex, Gemini/Antigravity; a universal router degrades all of them, so it stays an autocomplete/QA sidecar, never orchestration); predelete_check.sh fail-closed rewrite; memory-hygiene A-TMA anchor. New in 1.4.48: phantom-quench + steel-quench gain external frontier anchors (arXiv:2607.02052 package-hallucination; arXiv:2607.02057 prompt-coverage-adequacy); README model-flat claim reframed from a per-release point-curve to structural invariants (operation flattens across tiers; depth tier-order fixed within a generation). New in 1.4.47: onboarding step ① surfaces the Mode D companion-store session-start load in the auto-read salience anchor (previously only in the local binding + rules, so a greeting could skip the load). New in 1.4.46: context-doctor command-output axis (route to rtk/proxy for verbose CLI stdout, complementing .claudeignore; risk-gated to token-scarce envs). New in 1.4.41: context-doctor 2026 trigger vocab (context engineering/rot/collapse) + phantom-citation hardening; hub measurement-integrity-checklist (cross-model measurement pre-flight: display-name pin/reps≥3/discriminating probe). New in 1.4.40: install-wizard queryable-wiki scaffold (INDEX + session-start read + R/W/C ingest). New in 1.4.39: auto-decorrelation (cross-family verifier sidecar recruitment) + video-ingest (capability-routed video ingestion). New in 1.4.x: verify-axis check-class taxonomy (mandatory-pass/measured/judged), no-reinvention Tier-0 inventory, 7-class failure taxonomy, Destructive-Op Gate, Wave-T (Temper), tier-floor governance, Mode D Model Notice, FC consent lane, default-Sonnet guidance. New in 1.3.0: public-surface-audit, field-harvest Mode B auto-trigger, 4-axis gate scope ext. Validated cross-CLI: Claude Code, Codex, Gemini.",
|
|
16
16
|
"source": "./plugins/fh-meta"
|
|
17
17
|
},
|
|
18
18
|
{
|
|
19
19
|
"name": "fh-commons",
|
|
20
|
-
"version": "2.0
|
|
20
|
+
"version": "2.2.0",
|
|
21
21
|
"description": "Project-agnostic utility skills — 5 skills (convergence-loop · deliberation · mcp-circuit-breaker · token-budget-gate · ko-tech-writer) + 1 agent (quench-challenger). Domain-independent utilities transplantable into any project.",
|
|
22
22
|
"source": "./plugins/fh-commons"
|
|
23
23
|
}
|
package/AGENTS.md
CHANGED
|
@@ -116,9 +116,32 @@ Because non-Claude runtimes do not auto-load Claude path rules, apply these rule
|
|
|
116
116
|
(2026-08-09) and §1-a-2 expanded them to six (2026-08-16)**: ⓐ different family · ⓑ standpoint ·
|
|
117
117
|
ⓒ isolated grounding · ⓓ third-party encounter · ⓔ first real use · ⓕ revert-and-observe.
|
|
118
118
|
Axes are separated by **what they received**, not by how adversarial they are — same input,
|
|
119
|
-
same blind spot, however many reviewers you add.
|
|
120
|
-
|
|
121
|
-
|
|
119
|
+
same blind spot, however many reviewers you add. ✅ **The machine layer now carries all six**
|
|
120
|
+
(2026-08-17): a marker dated on/after that day must write `axes-run:` with the **circled keys**
|
|
121
|
+
`ⓐ=… ⓑ=→standpoint ⓒ=… ⓓ=… ⓔ=… ⓕ=…`; markers dated earlier keep the old **ASCII four**
|
|
122
|
+
(`a b c d`) and are not retroactively blocked. 🟥 **The two arrays are not the same letters —
|
|
123
|
+
old `b` (first real use) is now `ⓔ`, old `d` (revert probe) is now `ⓕ`.** Copying an old line
|
|
124
|
+
forward silently swaps two axes and raises no error. **Which array a marker used is decided by
|
|
125
|
+
the date in its filename** (`< 2026-08-17` = old four). ⚠️ The notation is NOT the discriminator
|
|
126
|
+
— that claim stood in this file for part of 2026-08-17 and a hand-count of the corpus refuted it:
|
|
127
|
+
2 of the 4 circled-key markers on disk are dated 2026-08-10 and carry the OLD meanings. Aligning
|
|
128
|
+
the notation still helps going forward; it does not work backwards.
|
|
129
|
+
`standpoint:` remains the canonical field for ⓑ (the `axes-run` entry
|
|
130
|
+
is only a pointer to it, and a pointer at an empty field is blocked); **its value enum is still
|
|
131
|
+
validated by nothing** — that is the one remaining gap, and it is not the same thing as the axis
|
|
132
|
+
being unmechanized. Format spec: `.claude/rules/fh_4axis_gate.md §Marker axis fields`.
|
|
133
|
+
(Two drift corrections landed here on 2026-08-17: first this sentence said "four" while its own
|
|
134
|
+
next clause described the +1 — caught by the session-close ④-b CC↔Codex parity check — and then
|
|
135
|
+
the machine layer moved to six the same day.)
|
|
136
|
+
⚠️ Until 2026-08-17 this entry point added "**ⓓ has no field at all** — record it in prose".
|
|
137
|
+
That is now **false**: `ⓓ=` is a required key like the rest. The retraction is kept visible
|
|
138
|
+
rather than deleted, because a Codex-side reader who memorised the old line would otherwise
|
|
139
|
+
keep writing markers without ⓓ and see them blocked with no idea why.
|
|
140
|
+
🟥 ⓑ **standpoint is itself split** (2026-08-17): a STATIC read of the target's own files is
|
|
141
|
+
`tier1b` and **executes nothing**; `tier2`+ asserts that something was RUN — the discriminator is
|
|
142
|
+
mechanical, *name the command you ran and the output you saw*. Measured on one delta: the static
|
|
143
|
+
arm found 1, running the target's own suite found 2 more, one of which printed neither `FAIL` nor
|
|
144
|
+
`❌`. Execution is the half with no substitute; see `field_verdict_crossfamily_gate.md §7`. Read it before recording; §1-c
|
|
122
145
|
holds the sample limits — read it before citing. This record is self-attested and has no hook
|
|
123
146
|
behind it; it is closed by a different-family reader, not by writing it more carefully.
|
|
124
147
|
8. **Branch-surface claims:** GitHub branch protection is two independent layers — legacy
|
package/CLAUDE.md
CHANGED
|
@@ -50,7 +50,7 @@ core invariants never melt). The nursery also **verifies what it births**: harne
|
|
|
50
50
|
> 4-Axis Auto-Gate 와 **같은 트리거**이므로 새 트리거도 새 파일도 만들지 않는다 — 기록 자리는
|
|
51
51
|
> **4축 마커의 기존 필드**(`axis2-*` · `axis3-*` · `residual`)다.
|
|
52
52
|
> **마커에 반드시 남는 3줄** ① **①영혼** — 설계 *전에* 쓴 «성공 정의 / 절대 안 함»(없으면 `없음`)
|
|
53
|
-
> · ② **돌린 축과 안 돌린 축을 각각 이름으로.** 마커 `axes-run`
|
|
53
|
+
> · ② **돌린 축과 안 돌린 축을 각각 이름으로.** 마커 `axes-run` 은 **2026-08-17 부로 여섯 글자**를 요구한다 — **기호 키**(ⓐ계열 · ⓑ입장 · ⓒ격리 그라운딩 · ⓓ3자대면 · ⓔ첫실사용 · ⓕ되돌림). 그 전 날짜의 마커는 옛 **ASCII 네 글자**(a·b·c·d) 그대로다. 🟥 **두 배열은 같은 글자가 다른 축을 가리킨다** — 옛 `b`=첫실사용은 지금 **ⓔ**, 옛 `d`=되돌림은 지금 **ⓕ** 라서, 옛 줄을 그대로 옮기면 축 둘이 조용히 뒤바뀌고 아무 오류도 안 난다. **어느 배열인지는 마커 파일명의 날짜로 판별한다**(`< 2026-08-17` = 옛 4축). ⚠️ **표기법은 판별자가 아니다** — 초판이 «기호 키를 보면 6축인 줄 안다» 고 적었는데 **코퍼스 실측이 반증했다**: axes-run 보유 53건 중 기호 키가 4건인데 그중 **2건이 2026-08-10 자이면서 옛 4축 의미로 기호를 쓴다**(`ⓑ 첫실사용` · `ⓓ 되돌림` — 현 배열에선 각각 ⓔ·ⓕ), 혼용도 1건 있다. 훅은 그 셋을 안 읽으므로 커밋은 안 막지만 **감사자의 grep 은 거기서 틀린 답을 낸다**. ⓑ입장은 값을 여기 적지 않고 **`standpoint:` 자기 필드**를 가리킨다(`ⓑ=→standpoint`, 그 줄이 비면 죽은 포인터라 차단). 즉 산문 정본과 기계가 **축 개수로는 맞았고**, 남은 어긋남은 `standpoint:` 값을 **검증하는 코드가 아직 0줄**이라는 것 하나다(명시된 잔여). 형식 정본 = `.claude/rules/fh_4axis_gate.md §Marker axis fields`
|
|
54
54
|
> · ③ **각 축의 컨트롤과 그 생사**. 축을 «돌렸다»의 **최소 증거 = 컨트롤이 살아 있는 실행 출력**
|
|
55
55
|
> 이다 — 안 고른 이유만 적은 것은 준수가 아니다.
|
|
56
56
|
> **비용 경계**: 넷을 매번 다 돌리지 않는다. 실패 모드에 맞춰 **고른다**.
|
|
@@ -122,6 +122,142 @@ onto their single hardest sub-mechanism, and a failure from a **non-harness** ru
|
|
|
122
122
|
metric — each read a live-but-incomplete thing as zero, each caught by the operator, not self-caught.
|
|
123
123
|
Detail: `[[feedback_reinvention_reflex_normalization_counterweight]]`.)
|
|
124
124
|
|
|
125
|
+
## Mechanization Boundary — machinery at irreversible edges and channels, judgment left to evolution
|
|
126
|
+
|
|
127
|
+
**Operator thesis (2026-08-16, verbatim)**: *"기계는 비가역 경계와 채널에만 두고, 판단은 진화에
|
|
128
|
+
맡긴다. 「한 모델로도 도달하지만 진화에 기대어 100%를 뽑는다」는 그 형태에서만 성립한다 — 판단을
|
|
129
|
+
내가 코드로 굳혀두면 그게 바로 진화를 막는 천장이 되니까."*
|
|
130
|
+
|
|
131
|
+
This is the standing answer to *"should this become a check?"*, and it is **not** "mechanize less":
|
|
132
|
+
|
|
133
|
+
| Build machinery | Leave to judgment |
|
|
134
|
+
|---|---|
|
|
135
|
+
| **Irreversible boundaries** — publish · delete · history-rewrite · anything a stranger can observe | Whether a given review was deep enough |
|
|
136
|
+
| **Channels** — that a typed field carries a value, that a verdict is typed not grepped, that grounds are attributable | What the right value *is* |
|
|
137
|
+
|
|
138
|
+
The discriminator: does the check assert a **property of the record** (present · typed · attributable ·
|
|
139
|
+
non-vacuous), or does it assert a **conclusion**? The first is a channel and ages well. The second
|
|
140
|
+
freezes today's judgment into tomorrow's ceiling — and this repo's own thesis is that the model layer
|
|
141
|
+
converges upward while the harness persists, so a frozen conclusion is a harness that gets *worse*
|
|
142
|
+
relative to what it wraps.
|
|
143
|
+
|
|
144
|
+
**Corollary — tier-visible behavior is not automatically a defect.** Some FH capability only becomes
|
|
145
|
+
reachable at a higher tier. `sonnet_floor_doctrine.md` is unchanged and remains a floor: **base ops
|
|
146
|
+
must run 100% at Sonnet, and a tier-gated *base op* is still a defect.** What this corollary adds is
|
|
147
|
+
the other side — where the gap is in *judgment quality* rather than in whether the capability fires,
|
|
148
|
+
the answer is not always to encode the judgment. Discipline and channel-typing are how Sonnet reaches
|
|
149
|
+
it; a frozen rule is how nobody ever exceeds it.
|
|
150
|
+
|
|
151
|
+
⚠️ **Applied honestly to this file's own machinery, same day**: the `declined`-grounds lane added to
|
|
152
|
+
`templates/.git-hooks/pre-commit` is a **channel** check (a claim must name attributable grounds) —
|
|
153
|
+
it does not judge whether decorrelation was warranted. But its grounds test is a *vocabulary grep*,
|
|
154
|
+
and a vocabulary list is a small frozen judgment: a legitimately-phrased `declined` in unforeseen
|
|
155
|
+
wording over-blocks. Accepted because the failure is **loud and cheap** (author rephrases) rather
|
|
156
|
+
than silent, and because it mirrors the existing degrade-branch form — named here rather than
|
|
157
|
+
claimed pure.
|
|
158
|
+
|
|
159
|
+
## Local Execution First — CI is a backstop, never the discovery mechanism
|
|
160
|
+
|
|
161
|
+
**Operator, 2026-08-16**: *"이 실패가 CI 확인 단계에서야 발견되는 건 매우 늦다 … 로컬에서 그
|
|
162
|
+
[대상 레포]를 통해서 실제로 구동시켜 봤다면 안 발생했을까"* and *"CI 확인도 중요하지만 사실 이는
|
|
163
|
+
**깃헙의 기능에 기대는 것**이라고 봐야 하려나."*
|
|
164
|
+
|
|
165
|
+
Both halves are load-bearing. **Late**: a red CI check is discovery at the slowest, most expensive
|
|
166
|
+
point in the loop, after push, after the PR, in front of an audience. **Borrowed**: CI is a
|
|
167
|
+
*platform* feature, so a harness that only finds its own defects there has not built a gate — it has
|
|
168
|
+
outsourced one, and it silently inherits that platform's coverage boundaries as its own.
|
|
169
|
+
|
|
170
|
+
**The order**: run the target's own suite locally, **to completion**, before pushing. Then let CI
|
|
171
|
+
confirm. A green CI on a change whose suite was never run locally is not a second opinion — it is the
|
|
172
|
+
*first* one.
|
|
173
|
+
|
|
174
|
+
**Why "to completion" is the operative phrase** (measured 2026-08-16, pmh-dev): that repo's
|
|
175
|
+
`validate.yml` was wired the same day, so CI's first run was the suite's first real execution ever —
|
|
176
|
+
there was no "previously known-good" for it to confirm. A partial local run would have missed it too:
|
|
177
|
+
the suite printed `SELFCHECK: FAIL` while **neither `FAIL` nor `❌` appeared anywhere in its output**
|
|
178
|
+
(the failing lane used its own vocabulary, `INSTRUMENT ERROR`), so locating it needed `bash -x` to
|
|
179
|
+
the actual failing line. Reading the tail, grepping for the expected token, or trusting an exit code
|
|
180
|
+
you did not trace are all forms of not-running-it.
|
|
181
|
+
|
|
182
|
+
**Relationship to the standpoint axis**: this is that axis's execution half, applied to your own
|
|
183
|
+
change rather than to a peer harness — see `field_verdict_crossfamily_gate.md §7`
|
|
184
|
+
«execution is the load-bearing half». Same principle, two surfaces.
|
|
185
|
+
|
|
186
|
+
## Skeleton, Not Muscle — a wiring change is DONE when the floor tier executes it
|
|
187
|
+
|
|
188
|
+
**Operator, 2026-08-16, verbatim**: *"배선에 대한 건 소넷이 실제로 돌아갈 수 있는지 봐야 잘 된
|
|
189
|
+
거니까. **근육이 아니라 뼈대 기준으로 돌아야 하는 거야.**"* — and, on having had to ask for it:
|
|
190
|
+
*"초기라서 내가 계속 이렇게 해봐라고 메뉴얼로 요청하고 있는데 **알아서 해야 할 거야.**"*
|
|
191
|
+
|
|
192
|
+
**근육(muscle)** = a strong model's raw capability carrying a rule that is not actually wired.
|
|
193
|
+
**뼈대(skeleton)** = the harness itself — the structure that makes the rule fire regardless of who
|
|
194
|
+
is running. A rule that only works because the session was smart enough is not wired; it is being
|
|
195
|
+
*carried*. It fails silently the moment a Sonnet session, a fresh install, or a compacted context
|
|
196
|
+
picks it up — which is every install that is not the author's.
|
|
197
|
+
|
|
198
|
+
**So the definition of done changes.** For any salience-dependent change (a rule, a trigger, an
|
|
199
|
+
enum value, an onboarding path, a doctrine line), "done" is **not** «the text is correct and a
|
|
200
|
+
reviewer agrees». It is: **a blind session at the floor tier, given a realistic situation and not
|
|
201
|
+
told which rule is being tested, actually fires it.** This upgrades `fh_4axis_gate.md`'s target-tier
|
|
202
|
+
sim gate from a near-mandatory step into the completion criterion itself.
|
|
203
|
+
|
|
204
|
+
**And it is self-dispatched.** Do not wait to be asked to run it. The operator asking *"소넷이 실제로
|
|
205
|
+
돌아갈지 확인은 하겠지?"* is the failure — the sim is part of authoring the change, like the
|
|
206
|
+
known-pair is part of authoring an instrument.
|
|
207
|
+
|
|
208
|
+
**Why «reads correctly» is not evidence.** A `tier1b` rung was added to the `standpoint:` enum
|
|
209
|
+
precisely so a static review would stop being recorded as `tier2`. The text was correct; a reader
|
|
210
|
+
would agree — and a reader agreeing is not a measurement, which is this paragraph's whole point.
|
|
211
|
+
|
|
212
|
+
🟥 **RETRACTED (2026-08-17) — the numbers this paragraph used to cite are withdrawn, in BOTH
|
|
213
|
+
directions.** It read: *"Two independent blind Sonnet sims then graded a pure cold-read as `tier2`,
|
|
214
|
+
**0/2** … A static read of my own fix would have scored it PASS. Only running it found the hole."*
|
|
215
|
+
That sim set was **8 runs at `tool_uses: 0`** — the agents never opened a file, so the instrument
|
|
216
|
+
was dead and the grades measure nothing (`tracks/_meta/fh_completed_2026-08-16.md:690`, retracted
|
|
217
|
+
the same day the doctrine was written and **before** this paragraph's own commit). The re-run with a
|
|
218
|
+
live instrument then landed the **opposite** result — the rung was graded correctly — at **reps=1**,
|
|
219
|
+
below this repo's own `reps>=3` bar. **So neither «it failed» nor «it worked» is established.** Do
|
|
220
|
+
not restore either number, and do not read the retraction as proof of the inverse.
|
|
221
|
+
|
|
222
|
+
**The claim that survives is narrower and does not need those numbers**: a static read cannot
|
|
223
|
+
establish that a rule *fires*, because the thing being tested is whether a reader who is not the
|
|
224
|
+
author lands on the right rung — and the author reading their own text is the one reader guaranteed
|
|
225
|
+
to. That is an argument about what a read can measure, not a measurement. The general principle
|
|
226
|
+
(`field_verdict_crossfamily_gate.md §7`'s execution-over-static asymmetry) rests on its own separate
|
|
227
|
+
field evidence; **this paragraph is no longer one of its data points.**
|
|
228
|
+
|
|
229
|
+
**Corollary — what a sim failure means.** It is a defect in the *wiring*, not in the floor model.
|
|
230
|
+
The response is to make the rule fire (disambiguate, give it a mechanical discriminator, move it to
|
|
231
|
+
where the actor reads it) — never to conclude the tier is too weak and move on. That conclusion is
|
|
232
|
+
how a harness quietly becomes tier-gated, which `sonnet_floor_doctrine.md` calls a defect of the
|
|
233
|
+
same severity class as a phantom reference.
|
|
234
|
+
|
|
235
|
+
### Scope, and the target state it exists for (operator, 2026-08-16)
|
|
236
|
+
|
|
237
|
+
**Scope — not FH-only**: *"FH뿐만이 아니라 **기계화 뼈대를 통해서 돌아가는 것들은 다** 이러한 과정을
|
|
238
|
+
거쳐야 제대로 돌아가는지 아닌지 파악할 수 있을 거니까."* Anything whose behavior depends on a
|
|
239
|
+
mechanized skeleton is in scope: field harnesses, propagated `templates/`, a mapped project's own
|
|
240
|
+
gates, **and code contributed upstream to someone else's repo**. The question «does this actually
|
|
241
|
+
fire for a reader who is not me, at the floor tier?» does not become optional because the artifact
|
|
242
|
+
lives outside this repo.
|
|
243
|
+
|
|
244
|
+
**Target state**: *"나머지는 정말 **저자(인간 저자)의 취향만** PR에서 첨삭할 수 있도록 하는 게
|
|
245
|
+
목표야."* A PR should arrive with every **mechanical** question already settled — does it fire ·
|
|
246
|
+
does it degrade in the safe direction · does the floor tier execute it · is the claim reproducible —
|
|
247
|
+
so that the only thing left for the human reviewer is **taste**: naming, framing, whether this is
|
|
248
|
+
the change they want. Review time spent re-deriving whether the thing works is review time
|
|
249
|
+
*taken from* the judgment only a human can supply.
|
|
250
|
+
|
|
251
|
+
**Existence proof, ours, this session**: *"우리가 최근에 클로드온데스크에 기여한 것처럼."*
|
|
252
|
+
`rullerzhou-afk/clawd-on-desk` PR #888 was merged **exactly as submitted, with no changes
|
|
253
|
+
requested** — the owner's words: *"focused, technically sound, and well-tested … we merged it
|
|
254
|
+
exactly as submitted, with no changes needed."* That is the shape: the mechanical case was closed
|
|
255
|
+
before submission (a fixture whose potency was reasoned about in-comment, a lane that re-executes
|
|
256
|
+
the real consumer path rather than asserting a flag), so nothing was left to negotiate but whether
|
|
257
|
+
they wanted it. **This is the bar to hold ourselves to on every outbound PR**, and it is why the
|
|
258
|
+
survivor-lane technique from that same PR is worth absorbing rather than admiring
|
|
259
|
+
(`tracks/_meta/fh_signal_2026-08-16_clawd-survivor-lane-air.md`).
|
|
260
|
+
|
|
125
261
|
## Instrument Calibration — before you trust a number, prove the instrument works *here*
|
|
126
262
|
|
|
127
263
|
An instrument (a scan, a grep, a checker, a diagnostic row, a metric) is a claim about the world only
|
|
@@ -387,12 +523,27 @@ raises resolution *within* one standpoint (the author's own repo, the author's o
|
|
|
387
523
|
target's rules); it does not decorrelate the review's ground-truth source. For a **shared-body /
|
|
388
524
|
cross-harness-boundary** change — scoped by *effect* (alters another harness's behavior, gate
|
|
389
525
|
outcome, or interaction contract), not merely by touching a synced file path — the marker
|
|
390
|
-
additionally carries `standpoint:` — a closed enum (`tier1` content-only ·
|
|
391
|
-
|
|
526
|
+
additionally carries `standpoint:` — a closed enum (`tier1` content-only · **`tier1b(<harness>)`
|
|
527
|
+
STATIC read of the target's own files, executed nothing** · `tier2(<harness>)`
|
|
528
|
+
peer-simulated, **EXECUTED CODE in** the target's own repo — 🟥 the discriminator is mechanical:
|
|
529
|
+
*name the command you ran and the output you saw*; cannot name one → `tier1b`, always. Reading the
|
|
530
|
+
target's real files, however cold, is `tier1b` (🟥 the "two blind Sonnet sims graded a cold-read
|
|
531
|
+
`tier2`" citation that stood here is **RETRACTED** — dead instrument, `tool_uses: 0`; the live re-run
|
|
532
|
+
inverted it at reps=1, below bar. The **rule** stands on its own wording, not on that sim) ·
|
|
533
|
+
`tier2b(<harness>)` same operator, target's real
|
|
392
534
|
runtime (local wiring visible, not independent) · `tier3(<harness>)` a *different* operator of the
|
|
393
535
|
target harness ran it · `not-applicable` · degrade triad `DEGRADED_NO_TARGET_ACCESS` could-not /
|
|
394
536
|
`DEGRADED_NOT_RUN` did-not / `UNKNOWN` did-not-look — same shape as `crossfamily:`'s triad,
|
|
395
|
-
**distinct literal values**, do not reuse crossfamily's tokens).
|
|
537
|
+
**distinct literal values**, do not reuse crossfamily's tokens).
|
|
538
|
+
🟥 **The execution is the load-bearing half** (operator decision 2026-08-16): a static standpoint
|
|
539
|
+
read competes with cross-family review for the same defect classes and mostly loses — *running the
|
|
540
|
+
target harness locally, to completion*, is the part with no substitute. Measured on one delta the
|
|
541
|
+
same day: static read found 1, running the target's own suite found 2 more, one of which printed
|
|
542
|
+
neither `FAIL` nor `❌` and was unreachable by any read. So **`tier2`+ asserts something was RUN** —
|
|
543
|
+
if the review only read, it is `tier1b`, and `tier1b` is deliberately the weak rung so that
|
|
544
|
+
recording it honestly surfaces that the execution arm is still owed. (Broken on the day it was
|
|
545
|
+
written — a static read was recorded as `tier2` because `tier1b` did not yet exist; a missing rung
|
|
546
|
+
gets filled by the next one up rather than staying empty.) Naming note: this collides in
|
|
396
547
|
English with FH's own persona/viewpoint sense of "standpoint" (`fh-meta:beginner`/`main-player`/
|
|
397
548
|
`expert`) — a different axis (which persona reviews, not whose repo is ground truth); kept as-is,
|
|
398
549
|
not renamed, but do not conflate the two. **Prose-only today** — unlike `crossfamily:`, no
|
|
@@ -615,6 +766,7 @@ Proposal format: `"I see [X]. Want me to run /[skill] to [one-line description]?
|
|
|
615
766
|
| **"이 절 잘라도 되나", "상주에서 빼자", "cut this section", "is this section load-bearing", "ablate this"** — a proposal to REMOVE resident text (the decision `/context-doctor` and `/salience-splitter` reach, not the routing to them) | **Ablation procedure — do not decide by eye.** Canon = `scripts/probe_scope_check.sh` header (arms · isolation · `reps>=3` · pre-registration · the two leak channels); runner precondition = `bash scripts/ablation_calibrate.sh` exits 0; verdicts land in `.claude/regression/ablation_verdicts.md`. **A section is CUT only on a pre-registered question set an isolated arm B answers correctly** — "I read it and it looks redundant" is not a measurement, and arm B answering *confidently wrong* is a KEEP, not a pass |
|
|
616
767
|
| "wrap up this week", "review", "audit", "weekly", "retrospective" | `/harvest-loop` |
|
|
617
768
|
| "pull this into FH", "reverse-harvest", "worth keeping", "harvest pattern", "field pattern" | `/field-harvest` |
|
|
769
|
+
| **you installed or invoked an EXTERNAL asset (a tool, framework, or repo not ours) and ran it against something this hub owns** — `pip install`/`npm i` of an outside framework, cloning a peer repo to run it, adopting an upstream utility. Fires on the ACT, not on a keyword: the trigger is *"I reached outside because ours did not cover this"* | **Sister Asset Protocol** (`knowledge/shared/rules/sister_asset_protocol.md` §Active adoption) — record the resolution difference, list **items to import** AND **items the hub can propagate** (bidirectionality is a prohibition, not a nicety), and where there is no write access write a `tracks/_audit/proposal_*.md` so the operator can decide whether to contribute it upstream. 🟥 Missed 2026-08-16 on exactly this shape: an external red-team framework was installed, run against a field harness, found a real bypass — and was filed as a `type: reference` **tool pointer** with no sister audit at all |
|
|
618
770
|
| "용광로모드", "crucible mode", "absorb this whole corpus", "throw everything in", "re-forge FH identity", "melt this down" (total-immersion absorption, not cherry-pick — esp. a whole corpus on a core FH axis, or a frontier showcase risking FOMO) | `knowledge/shared/harness-core/crucible_mode.md` (read it, run the chain: total-ingest → steel-quench/phantom-quench melt → governor identity-bonding → sim/persona reforge → field-harvest rebirth; the core invariants stay unmeltable) |
|
|
619
771
|
| "review this PR", "check diff", "code review" | code diff → built-in `/code-review`·`/review` · FH-asset coherence → `/hub-cc-pr-reviewer` (role split) |
|
|
620
772
|
| "keep watching X", "poll this", "check every N minutes", recurring WATCH item | built-in `/loop` (interval runner) — pair with the WATCH list, don't hand-poll |
|
|
@@ -660,6 +812,40 @@ At session start, determine the last run time from history files and auto-propos
|
|
|
660
812
|
|
|
661
813
|
> A cadence reminder the user has repeatedly declined is **muted** per the UAP (see the loop below) — don't re-nag.
|
|
662
814
|
|
|
815
|
+
#### Expedition (원정) — measured first, cadence only if it earns one
|
|
816
|
+
|
|
817
|
+
**Operator, agreed and recorded 2026-08-17** (it had been agreed verbally before and was **not in any
|
|
818
|
+
file** — grepped, zero hits; that gap is why this paragraph exists): *"원정이 가치 있고 성공적이었다면
|
|
819
|
+
**주기적으로 제안하는 것**으로 가기로 했었지."*
|
|
820
|
+
|
|
821
|
+
An **expedition** is a deliberate, extended run that uses the harness cluster at full stretch against
|
|
822
|
+
targets outside this hub — contributing to an external repo, declaring a peer's assets as cluster
|
|
823
|
+
nodes, driving a foreign codebase through FH's own gates. Its operating conditions are unusual and
|
|
824
|
+
must not be judged by another track's: **token cost is expected and pre-approved** (the `/goal-quench`
|
|
825
|
+
budget gate still applies — approval removes the prompt, never the gate), **one session will not
|
|
826
|
+
finish it**, and the success definition is not "expedition completed" but ⓐ **finding the pieces that
|
|
827
|
+
move identities to 🟢 faster than internal work would** and ⓑ **hardening existing weak points by
|
|
828
|
+
stressing them somewhere real**. An expedition that builds nothing and produces those two has succeeded.
|
|
829
|
+
|
|
830
|
+
**Promotion path — and the interval is set AFTER the first one, not before** (operator, 2026-08-17:
|
|
831
|
+
*"그 주기를 얼마나에 한 번씩 잡아야 할지도 그때 세우도록 할게 — 원정 한 차례 다 마치고 답습한 후에"*).
|
|
832
|
+
Expeditions are **not** on a cadence today; they are proposed case-by-case.
|
|
833
|
+
|
|
834
|
+
Sequence, in order, and do not skip to the end:
|
|
835
|
+
1. **Run one, all the way through.** Not a slice — a complete expedition, however many sessions it
|
|
836
|
+
takes (the thread-continuation block on the session card is the carrier).
|
|
837
|
+
2. **Absorb it** (답습) — what came back, what it cost, what it hardened, what it found that internal
|
|
838
|
+
work would not have.
|
|
839
|
+
3. **Then set the interval**, informed by (2). An expedition's cadence has to be derived from what one
|
|
840
|
+
actually costs and yields — a number picked before the first run is a guess wearing a schedule.
|
|
841
|
+
|
|
842
|
+
⚠️ **This deliberately does NOT use the `operations.md` `accepted ≥ 60%` promotion gate.** That gate
|
|
843
|
+
measures how often a proposal class is *accepted*, which is the wrong quantity here: an expedition
|
|
844
|
+
could be accepted every time and still not warrant a schedule, or be proposed once and clearly warrant
|
|
845
|
+
one. The evidence that sets the interval is the **completed run itself**, not an acceptance rate.
|
|
846
|
+
**No new gate, no new cadence table, no new registry** either — when the interval is set, it graduates
|
|
847
|
+
into the existing §Cadence-Rules table like any other row.
|
|
848
|
+
|
|
663
849
|
#### Event-bound proposals (context-entry, not time)
|
|
664
850
|
|
|
665
851
|
Some proposals are not *time*-overdue — they fire **once when a specific work context is entered**. `persona-innovator` (ideation/naming + external-frontier absorption) is most valuable in exactly two contexts and friction-noise everywhere else, so it is proposed on context-entry rather than every session or every N days:
|
|
@@ -988,6 +1174,37 @@ Closing phrase detected ("wrap up", "done", "good work", "end session", etc.)
|
|
|
988
1174
|
across `package.json` + every `.claude-plugin/plugin.json` + `.claude-plugin/marketplace.json` (single-source =
|
|
989
1175
|
`package.json`) → Pre-Publish gate → `npm publish` → `git tag vX.Y.Z` at publish. **Propose, don't
|
|
990
1176
|
auto-publish.** (Why lockstep — Codex caches on plugin.json version — + drift-check + tag-drift caveat → §detail below.)
|
|
1177
|
+
|
|
1178
|
+
🟥 **WHICH DIGIT — operator decision 2026-08-17, and it is deliberately NOT strict semver.**
|
|
1179
|
+
There was no policy before this line, which is why one session proposed three different bumps
|
|
1180
|
+
for the same delta on three different (and each individually defensible) grounds. Decide by
|
|
1181
|
+
**what the number tells a reader**, not by whether anything technically broke:
|
|
1182
|
+
|
|
1183
|
+
| Bump | Reserved for (operator's own wording, 2026-08-17) |
|
|
1184
|
+
|---|---|
|
|
1185
|
+
| **major** `+1.0.0` | **any one of three**: ⓐ **완전히 새로 지음** — rebuilt from scratch, not extended · ⓑ **정체성이 확립됨** — an identity of the five (+Ⓑ) actually standing 🟢, not progressing toward it · ⓒ **기능이 혁신적으로 변경되거나 늘어남** — a capability *class* appears or is replaced, not a capability instance. 🟥 **Never** for tightening a gate that already existed |
|
|
1186
|
+
| **minor** `+0.1.0` | 미들급 — new assets, new gate lanes, doctrine that changes behavior; **including changes that break a consumer's gate acceptance**, which then carry a mandatory `BREAKING (gate):` line |
|
|
1187
|
+
| **patch** `+0.0.1` | 트리비아급 — fixes, wiring, docs that change no behavior |
|
|
1188
|
+
|
|
1189
|
+
**The discriminator between major-ⓒ and minor**: *class* vs *instance*. A sixth Wave-1 attack
|
|
1190
|
+
angle is an instance → minor. An attack-angle **registry** where none existed is a class → major.
|
|
1191
|
+
Today's delta is instances and tightenings throughout, which is why it is 2.1.0 and not 3.0.0
|
|
1192
|
+
even though it breaks a gate acceptance.
|
|
1193
|
+
|
|
1194
|
+
**Why gate-tightenings are minor here, stated so it is not mistaken for hiding a break**: what
|
|
1195
|
+
breaks is the **record format of a gitignored local marker**, not an API or the consumer's code;
|
|
1196
|
+
the hook prints exactly what to write instead; and the blast radius needs the consumer to have
|
|
1197
|
+
installed the hook AND be making a load-bearing change AND have used the specific old form.
|
|
1198
|
+
Against that, strict semver would burn a major on every gate we tighten — this repo took 2.0.0
|
|
1199
|
+
for a publish-freshness gate one day and would have taken 3.0.0 for a commit gate the next.
|
|
1200
|
+
**A major number that arrives monthly stops meaning anything**, and the milestone it should be
|
|
1201
|
+
reserved for would have no word left.
|
|
1202
|
+
|
|
1203
|
+
⚠️ **The condition that makes this honest, and it is not optional**: a minor that breaks gate
|
|
1204
|
+
acceptance MUST carry `BREAKING (gate): <what now blocks> — <the one-line remedy>` in the
|
|
1205
|
+
release description AND the CHANGELOG. Without it this policy is just burying breaks in minors.
|
|
1206
|
+
**Applies from 2026-08-17 forward, not retroactively** (2.0.0 was the same class and is left
|
|
1207
|
+
as-is rather than rewritten).
|
|
991
1208
|
→ ④-c Handoff lifecycle (cross-machine continuity) — when a durable **result artifact lands** this
|
|
992
1209
|
session (mechanical hint: a new `*result*`/`*signal*`/`*_run_*` file in your companion store or
|
|
993
1210
|
`tracks/`), do two things: **(a) ④-c stamps** any `"run this/start here"` run-handoff whose
|
|
@@ -1050,6 +1267,25 @@ Card update is NOT a sub-step of harvest-loop — even if harvest-loop is skippe
|
|
|
1050
1267
|
① **Agent View pre-read** (see above) → ② Step 0-b cross-check generates removal list → ③ Remove completed items → ④ Add new priorities → ⑤ Fix stale paths/versions → ⑥ Overwrite → ⑦ Output "BEFORE N items → AFTER M items" diff.
|
|
1051
1268
|
"Delta update" not "snapshot" — completed items remaining in next session card is a bug.
|
|
1052
1269
|
|
|
1270
|
+
**Thread-continuation block (operator, 2026-08-16)**: *"특정 주제에 집중해서 진행한 세션이라면
|
|
1271
|
+
앞으로도 마감할 때 그 갈래로 이어갈 수 있게 알아서 정리해줘."* When a session ran predominantly on
|
|
1272
|
+
**one thread** (an incubation, one field harness, one doctrine arc) — as opposed to scattered
|
|
1273
|
+
maintenance — the card additionally carries a **named continuation block for that thread**, without
|
|
1274
|
+
being asked:
|
|
1275
|
+
|
|
1276
|
+
```
|
|
1277
|
+
🧵 <thread name> — 이어가려면
|
|
1278
|
+
지금 어디 : <state, with the artifact that proves it — a verdict line, a test count, a merged PR>
|
|
1279
|
+
다음 한 걸음: <the single next action, concrete enough to start without re-deriving>
|
|
1280
|
+
안 닫힌 것 : <what is open, stated as open — not omitted>
|
|
1281
|
+
읽을 것 : <the 1-3 files that reconstitute context, in read order>
|
|
1282
|
+
```
|
|
1283
|
+
|
|
1284
|
+
Not a second card and not a summary of the session — it is the **entry point for the next session
|
|
1285
|
+
that picks up this thread**, and it is written so that session does not have to re-derive where the
|
|
1286
|
+
thread stood. A scattered-maintenance session correctly writes none. Two or more threads → one block
|
|
1287
|
+
each, in priority order.
|
|
1288
|
+
|
|
1053
1289
|
## Session Sync / Knowledge Push Protocol
|
|
1054
1290
|
|
|
1055
1291
|
> Detailed procedure: `knowledge/shared/rules/sync_push_protocols.md`
|
|
@@ -345,6 +345,74 @@ the governor / mechanical-anchor doctrine, applied at registration instead of at
|
|
|
345
345
|
|
|
346
346
|
---
|
|
347
347
|
|
|
348
|
+
## ⓒ Node Identity Declaration (operator-approved 2026-08-16)
|
|
349
|
+
|
|
350
|
+
### ⓒ.1 The gap this closes
|
|
351
|
+
|
|
352
|
+
The eight axes of §ⓐ.2 are properties **of a harness**, not of any one function — `residency`,
|
|
353
|
+
`tier_floor`, `degrade`, `approval` describe what a node *is* and what it will not do. Yet today
|
|
354
|
+
they are declarable only **attached to a callable**. A node with a real identity and no
|
|
355
|
+
bar-clearing entry point therefore has no way to state what it is, and `cluster_capability_scan.sh`
|
|
356
|
+
prints it as `NONE 0` — **byte-identical to an empty directory**. That is `not found ≠ 0` at the
|
|
357
|
+
cluster layer: "has an identity, exposes no function" and "has nothing" are rendered as one value.
|
|
358
|
+
|
|
359
|
+
**This does not reopen §ⓑ.** That section deliberately refuses to register *prose* as a
|
|
360
|
+
capability, for a reason that still holds: prose does not fire without attention. An identity
|
|
361
|
+
declaration is not prose. It is the **same enum'd 8-axis vocabulary**, machine-readable, and it
|
|
362
|
+
merges under the §ⓐ operators exactly as a capability's `constraints:` block does. It fires by
|
|
363
|
+
being merged, not by being read.
|
|
364
|
+
|
|
365
|
+
### ⓒ.2 Refusal is the point, not a fallback
|
|
366
|
+
|
|
367
|
+
The most valuable thing many nodes have to declare is what they **will not** do. A field harness
|
|
368
|
+
whose canon says *"operates standalone — no external harness dependency"* is making a real claim,
|
|
369
|
+
and today that claim is a sentence nothing enforces: any composition attempt sails past it.
|
|
370
|
+
Declared as `approval: forbidden` / `residency: company`, the same claim **blocks the attempt
|
|
371
|
+
mechanically**.
|
|
372
|
+
|
|
373
|
+
So identity declaration is not a device for making every node joinable. It is a device for making
|
|
374
|
+
a node's boundaries enforceable instead of merely written down. A node that declares itself
|
|
375
|
+
uncomposable has declared successfully.
|
|
376
|
+
|
|
377
|
+
### ⓒ.3 Form
|
|
378
|
+
|
|
379
|
+
A node-level declaration carries `id`, `summary`, and the eight axes — and **no** `entry`,
|
|
380
|
+
`verdict_enum`, or calibration pair, because it exposes no call. It is not registrable as a
|
|
381
|
+
callable and must never be counted as one; the scan reports identity-declared and
|
|
382
|
+
capability-declared **separately**, or it recreates the collapse this section exists to fix.
|
|
383
|
+
|
|
384
|
+
`UNKNOWN` is a **first-class value and the required answer for any axis the declarer cannot
|
|
385
|
+
ground in its own files.** A profile with five `UNKNOWN`s and three cited axes is worth more than
|
|
386
|
+
eight plausible defaults, because the defaults are indistinguishable from measurements once
|
|
387
|
+
written. The §ⓑ.5 worst-case substitution applies unchanged at composition time: unknown is not
|
|
388
|
+
safe, and the runtime assumes the node can do the most and is allowed the least.
|
|
389
|
+
|
|
390
|
+
### ⓒ.4 Evidence (2026-08-16 self-declaration campaign, n=4 nodes)
|
|
391
|
+
|
|
392
|
+
Four peer harnesses were assessed from **their own** repositories, each asked to reach its own
|
|
393
|
+
verdict and to prove it by running FH's real registration bar. Their four outcomes are four
|
|
394
|
+
*different* failures, and the campaign's main result is that they are different:
|
|
395
|
+
|
|
396
|
+
| Node | callable | somewhere to put it | outcome |
|
|
397
|
+
|---|---|---|---|
|
|
398
|
+
| forge-wiki | ✅ clears the bar, known-pair separates | ✅ | `SHIP-READY` |
|
|
399
|
+
| the-bible | ✅ separates 4 ways live | ✅ | **bar cannot express it** — its entry takes stdin JSON; the schema drives calibration arms by argv only, so both arms ran empty and returned the same code |
|
|
400
|
+
| qasp-dev | ✅ clears the bar | ❌ — declaration path is outside the mirror-protected set, so it would travel to an organization mirror | `BLOCKED(mirror boundary)` |
|
|
401
|
+
| dashboard | — | — | identity resident; primary consumer is a different operator, so its exposure decision is not this operator's to make |
|
|
402
|
+
|
|
403
|
+
Three FH-side defects fell out of running the bar for real rather than reasoning about it:
|
|
404
|
+
the M3 model-independence test matched `*claude*` as a **substring**, so an entry whose *path*
|
|
405
|
+
contained that word was silently rejected as "calls a model CLI" (fixed — basename tokens);
|
|
406
|
+
the effect probe validates inside a `git clone --local`, so a declaration **cannot be validated
|
|
407
|
+
until it is committed**; and the schema has **no stdin channel**, which excludes an entire class
|
|
408
|
+
of callables from ever being declarable. The second and third are open.
|
|
409
|
+
|
|
410
|
+
Note what did *not* happen: no arm wrote a shim into a peer repo to make a failing candidate pass.
|
|
411
|
+
The stdin case was reported as an FH schema gap rather than patched at the field node — which is
|
|
412
|
+
the correct direction, and the one that would have been easiest to get wrong.
|
|
413
|
+
|
|
414
|
+
---
|
|
415
|
+
|
|
348
416
|
## 1. The two live constraints — answered, and what stays open
|
|
349
417
|
|
|
350
418
|
### Salience — does a reader meet these rules when they apply?
|