@chrono-meta/fh-gate 2.0.0 → 2.1.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.
Files changed (56) hide show
  1. package/.claude/capabilities/adapters/gstack-content-safety.cap +110 -0
  2. package/.claude/capabilities/adapters/mate-agent-boundary.cap +110 -0
  3. package/.claude/capabilities/adapters/qasp-new-code-anchor.cap +116 -0
  4. package/.claude/capabilities/degrade-direction-scan.cap +24 -0
  5. package/.claude/capabilities/public-surface-scan.cap +24 -0
  6. package/.claude/rules/fh_4axis_gate.md +77 -1
  7. package/.claude-plugin/marketplace.json +3 -3
  8. package/AGENTS.md +25 -3
  9. package/CHEATSHEET.md +17 -1
  10. package/CLAUDE.md +241 -5
  11. package/README.ja.md +55 -20
  12. package/README.ko.md +86 -20
  13. package/README.md +57 -20
  14. package/README.zh.md +49 -19
  15. package/knowledge/shared/harness-core/capability_composition_contract.md +68 -0
  16. package/knowledge/shared/harness-core/fh_three_layer_canon.md +122 -5
  17. package/knowledge/shared/harness-core/field_verdict_crossfamily_gate.md +115 -3
  18. package/knowledge/shared/harness-core/harness_incubator_doctrine.md +83 -1
  19. package/knowledge/shared/harness-core/harness_terminal_correlation_and_recommendations.md +255 -0
  20. package/knowledge/shared/harness-core/harness_verification_core_extended.md +1 -1
  21. package/knowledge/shared/harness-core/ship_readiness_gate.md +234 -11
  22. package/knowledge/shared/learnings/subagent_invocations_log.yaml +128 -0
  23. package/knowledge/shared/rules/sister_asset_protocol.md +12 -0
  24. package/package.json +12 -3
  25. package/plugins/fh-commons/.claude-plugin/plugin.json +1 -1
  26. package/plugins/fh-commons/agents/quench-challenger.md +6 -1
  27. package/plugins/fh-meta/.claude-plugin/plugin.json +2 -2
  28. package/plugins/fh-meta/CHANGELOG.md +60 -0
  29. package/plugins/fh-meta/skills/auto-decorrelation/SKILL.md +14 -2
  30. package/plugins/fh-meta/skills/steel-quench/SKILL_detail.md +13 -0
  31. package/plugins/fh-meta/skills/verify-bidirectional/SKILL.md +34 -1
  32. package/scripts/adapters/gstack_content_safety.sh +186 -0
  33. package/scripts/adapters/mate_agent_boundary.sh +120 -0
  34. package/scripts/adapters/peer_resolve.sh +99 -0
  35. package/scripts/adapters/qasp_new_code_anchor.sh +159 -0
  36. package/scripts/branch_claim.sh +14 -0
  37. package/scripts/capability_effect_probe.sh +340 -20
  38. package/scripts/capability_registry_check.sh +271 -20
  39. package/scripts/chamber_run.sh +24 -3
  40. package/scripts/chamber_witness.sh +25 -0
  41. package/scripts/cluster_capability_scan.sh +629 -0
  42. package/scripts/fh-gate.sh +16 -1
  43. package/scripts/fh_session_load.sh +70 -0
  44. package/scripts/package_coverage_check.sh +10 -0
  45. package/scripts/portability_lint.sh +257 -0
  46. package/scripts/prepublish_scope_note.sh +139 -0
  47. package/scripts/relay_channel.sh +70 -7
  48. package/scripts/selfcheck.sh +167 -5
  49. package/scripts/test_adapter_lanes.sh +296 -0
  50. package/scripts/test_capability_entrypoint_shipping.sh +8 -1
  51. package/scripts/test_fh_gate_regressions.sh +21 -9
  52. package/scripts/test_marker_axes_run_lanes.sh +87 -3
  53. package/scripts/test_marker_crossfamily_lanes.sh +31 -1
  54. package/scripts/test_relay_channel_lanes.sh +76 -0
  55. package/templates/.git-hooks/pre-commit +239 -12
  56. package/templates/subagent-tally-hook.json +2 -2
package/README.md CHANGED
@@ -198,7 +198,7 @@ this page: that table is *symptoms you might arrive with*, this is *what the hub
198
198
 
199
199
  | | Identity | What a person gets |
200
200
  |---|---|---|
201
- | **①** | **Multi-harness cluster** | One task rides several harnesses, and governance is computed *between* them |
201
+ | **①** | **Harness cluster** | One task rides several harnesses, and governance is computed *between* them. Its load-bearing sub-mechanism, **cross-harness**: **call** a capability you do not have (rather than build it), and **absorb** the one you should have built |
202
202
  | **②** | **Project incubator** | A new harness comes out **walking where it was born**, not as an empty scaffold |
203
203
  | **③** | **Governance gate** | What must not ship is blocked **mechanically**, not by remembering to check |
204
204
  | **④** | **Frontier → org propagation** | What arrives from outside lands all the way *inside* the organization |
@@ -244,8 +244,14 @@ four engines the capability that makes it possible (capability — what i
244
244
  ↑ produced by
245
245
  three-stage the ORDER those engines are forged in (process — how it gets made)
246
246
  process
247
+ └ stage ③ = the six-axis gate (§The six verification axes, below)
247
248
  ```
248
249
 
250
+ As a mnemonic: **three-stage process · four engines · five identities · six-axis gate**.
251
+ ⚠️ But **the six axes are not a fourth layer** — they are *what stage ③ of the three-stage process
252
+ consists of*. Read the four as parallel layers and you get back the very "the layers do not land"
253
+ problem this section was written to fix.
254
+
249
255
  **The four engines.** Each one is what some identity above is standing on. They were not invented for this
250
256
  page: the readiness gate had already been scoring every identity against these same four capabilities in a
251
257
  column of its own ([`ship_readiness_gate.md`](knowledge/shared/harness-core/ship_readiness_gate.md)), so
@@ -285,29 +291,60 @@ harness is actually used.
285
291
  direction of its own; the judgment circuit from ① is what picks.
286
292
  This is a way of WORKING, not the end-of-line check in ③.
287
293
 
288
- ③ Burn it down at the the four axes below. Adversarial review is ONE of them, not all of them
289
- end, on four axes
294
+ ③ Burn it down at the the six axes below. Adversarial review is ONE of them, not all of them
295
+ end, on six axes adversariality is a **posture**, not an axis. It can ride on any axis, and
296
+ riding it does not make that axis see what it cannot see
290
297
  ```
291
298
 
292
- **The four verification axes** — where "we reviewed it" usually turns out to mean only the first of them.
293
- Read the middle column to pick one, and the right column to see what it catches:
299
+ **The six verification axes** — where "we reviewed it" usually turns out to mean only the first of them.
300
+
301
+ 🟥 **Axes are not divided by *how adversarial* they are. They are divided by *what they were given*.**
302
+ Hand two reviewers the same input and **the same blind spot survives**, however many of them you add.
303
+ That is why the column that matters most below is *what it gets*:
294
304
 
295
- | Axis | Reach for it when… | What it catches | Typical instrument |
305
+ | Axis | **What it gets** | What it catches | Typical instrument |
296
306
  |---|---|---|---|
297
- | **ⓐ Different family** | the change decides something a PASS/FAIL, a gate, a safety rule | the **implementation** is wrong | a reviewer from another model family (`auto-decorrelation`) |
298
- | **ⓑ First real use** | you are about to trust a number, a count, or a scan's output | the **way you are measuring** is wrong | run it once against one real target and look at the result by hand |
299
- | **ⓒ Record grounding** | you wrote down claims, figures or citations others will act on | the **claim** is wrong | someone who did not write it re-measures what it says |
300
- | **ⓓ Revert and observe** | you added a test, a guard or a check and believe it protects you | the **anchor** is wrong the check is decorative | delete the thing it guards and confirm *that specific* check goes red |
301
-
302
- **You do not run all four every time, and that is the design.** A one-line fix earns none of them; a change
303
- that returns a verdict earns ⓐ; a published number earns ⓑ and ⓒ; a new guard earns ⓓ; an irreversible
304
- surface publish, delete, history rewrite earns whichever of the four its failure mode exposes, and the
305
- benefit of the doubt goes to running one more. Multiplying reviewers is not the same as adding an axis.
306
-
307
- One further axis sits outside this four because it changes *whose* ground truth you stand on rather than
308
- *what* you check: **standpoint** — when a change crosses into another harness, run the diff from the
309
- target's own repo and rules, not from your reading of them
310
- ([`field_verdict_crossfamily_gate.md §7`](knowledge/shared/harness-core/field_verdict_crossfamily_gate.md)).
307
+ | **ⓐ Different family** | the diff + the author's framing | the **implementation** is wrong | a reviewer from another model family (`auto-decorrelation`) |
308
+ | **ⓑ Standpoint** | the diff + **the target harness's own canon** | **whether the rule you cited actually says that** | run the diff from that harness's own repo and rules ([`§7`](knowledge/shared/harness-core/field_verdict_crossfamily_gate.md)) |
309
+ | **ⓒ Isolated grounding** | the sentences the author wrote + the tree as it stands now | the **claim** is wrong | someone who did not write it re-measures what it says |
310
+ | **ⓓ Third-party encounter** | the problem + **someone else's codebase** | **is this already solved** · where your change touches someone else's repo | look at the same problem in an unrelated third repo |
311
+ | **ⓔ First real use** | one real target | the **way you are measuring** is wrong — the instrument's instrument | run it once against one real target and check the result by hand |
312
+ | **ⓕ Revert and observe** | the tree with the wiring deleted | the **anchor** is wrong — the check is decorative | delete the thing it guards and confirm *that specific* check goes red |
313
+
314
+ **You do not run all six every time, and that is the design** do not multiply them, **choose**:
315
+
316
+ ```
317
+ one-line fix (typo · gitignore) nothing burns. Not even ①'s circuit when there is one answer,
318
+ planting one is overhead
319
+ ordinary code change (reversible) ⓔ first real use + revert
320
+ verdict · gate code + ⓐ different family — verdict logic is what a reviewer who
321
+ shares the author's optimism misses **structurally**
322
+ change that touches another + ⓑ standpoint — bolt on three families and if all three eat
323
+ harness your framing, nobody asks "does that canon actually say so"
324
+ very large · irreversible + ⓒ isolation + ⓓ third-party encounter. Burn all of it
325
+ ```
326
+
327
+ ⚠️ **ⓓ third-party encounter is the most expensive and has the smallest unique yield.** And yet that
328
+ handful were all of the **boundary-crossing** kind (a rule someone else had already retired · someone
329
+ else's repo importing your file). On small, reversible changes such items simply **do not arise**; on
330
+ large irreversible ones those two are exactly what becomes an incident. That is where the cost earns
331
+ itself.
332
+
333
+ **Why this is not superseded by base-model advances** — an axis is defined by its **input**, not by the
334
+ *reviewer's ability*. A stronger model still **cannot see information it was not given.** Scaffolding
335
+ sheds as models improve, but **input-boundary decorrelation does not**, and a single author cannot, by
336
+ definition, step outside their own input. 🟥 Honest edge: if the agent **fetches more input by itself
337
+ with tools**, the boundary blurs — an outside judgment held that "the store is never used in full" and
338
+ "the swallowed exception" are catchable by ⓐ and ⓒ as well, since those reviewers grep for themselves.
339
+ Conversely, "a rule another repo retired long ago" **cannot be fetched by any tool** — there is no reason
340
+ to have access to that project's review history in the first place. That is where ⓓ remains.
341
+
342
+ > 🟥 **Limits to read before citing this**: the six-axis table is **n=1** (one artifact · one session ·
343
+ > one author). Whether the axes' non-overlap is structural or an accident of that day is **unmeasured**.
344
+ > And when the author's self-scoring was stripped out — 16 findings handed, **with their provenance
345
+ > removed**, to two classifiers from other families for blind judgment — **3 of the 5** the author had
346
+ > attributed to ⓓ were judged to belong to a different axis; those three were not "what the axis was
347
+ > needed for" but "what another axis missed". Discount the table's attributions accordingly.
311
348
 
312
349
  > **Honest note — this is not a clean stack, and that is the point.** Stage ① and stage ③ are made of the
313
350
  > same material as the engines, so the lower layer uses the upper one. The contradiction resolves on
package/README.zh.md CHANGED
@@ -188,7 +188,7 @@ Project B ──→ 在 CLAUDE.md 中连接中枢
188
188
 
189
189
  | | 身份 | 一个人得到什么 |
190
190
  |---|---|---|
191
- | **①** | **多框架集群 (Multi-harness cluster)** | 一个任务同时驾驭多个框架,而治理是在它们 *之间* 算出来的 |
191
+ | **①** | **框架集群 (Harness cluster)** | 一个任务同时驾驭多个框架,而治理是在它们 *之间* 算出来的。承重的下位机制是 **跨框架 (cross-harness)** — 没有的能力就**调用**(而不是自己造),看到该造的就**吸收** |
192
192
  | **②** | **项目孵化器 (Project incubator)** | 新框架出炉时 **就已经会走路**,而不是一副空的脚手架 |
193
193
  | **③** | **治理门禁 (Governance gate)** | 不该出货的东西被 **机械地** 拦下,而不是靠记得去检查 |
194
194
  | **④** | **前沿 → 组织传导 (Frontier → org propagation)** | 从外部到来的东西,一路落进组织 *内部* |
@@ -230,8 +230,13 @@ Project B ──→ 在 CLAUDE.md 中连接中枢
230
230
  四大引擎 让它成为可能的那份能力 (能力 —— 它能做什么)
231
231
  ↑ 由此产出
232
232
  三段工序 那些引擎被锻造出来的「顺序」 (工序 —— 它是怎么被造出来的)
233
+ └ ③ 段 = 六轴门禁 (见下面的 §六条验证轴)
233
234
  ```
234
235
 
236
+ 便于记忆的形式是:**三段工序 · 四大引擎 · 五重身份 · 六轴门禁**。
237
+ ⚠️ 但 **六条轴不是第四层** —— 它们是三段工序里 **③ 段究竟由什么构成**。把这四者读成并排的层,
238
+ 就会把本节原本要修的那个「层立不起来」的问题重新招回来。
239
+
235
240
  **四大引擎。** 每一个都是上面某个身份所站立的地基。它们不是为这一页发明出来的:出货就绪门禁
236
241
  ([`ship_readiness_gate.md`](knowledge/shared/harness-core/ship_readiness_gate.md))早就用一个独立
237
242
  的列,按这同样四项能力给每一重身份打分,所以给它们命名是识别,而不是搭一套分类法。
@@ -268,28 +273,53 @@ Project B ──→ 在 CLAUDE.md 中连接中枢
268
273
  看两遍。并行本身没有方向,挑方向的是 ① 里那套判断坐标系。
269
274
  这是一种「工作方式」,不是 ③ 里那道收尾检查。
270
275
 
271
- 最后在四条轴上烧一遍 也就是下面那四条轴。对抗审阅只是其中一条,不是全部
276
+ 最后在六条轴上烧一遍 也就是下面那六条轴。对抗审阅只是其中一条,不是全部 —— 对抗性是一种
277
+ **姿态**,不是一条轴。它可以搭在任何一条轴上,但搭上去之后,那条轴
278
+ 看不见的东西照样看不见
272
279
  ```
273
280
 
274
- **四条验证轴** —— 所谓"我们审过了",往往到头来只做了其中第一条。看中间那列来挑一条,看右边那列
275
- 知道它能抓到什么:
281
+ **六条验证轴** —— 所谓"我们审过了",往往到头来只做了其中第一条。
282
+
283
+ 🟥 **轴不是按「有多对抗」来分的,是按「它拿到了什么」来分的。** 拿到的东西一样,你堆多少位审阅者,
284
+ **同一个盲点都会留下来**。所以下面这张表里最重要的一列是 *它拿到什么*:
276
285
 
277
- | 轴 | 什么时候该伸手拿它…… | 它抓到什么 | 典型手段 |
286
+ | 轴 | **它拿到什么** | 它抓到什么 | 典型手段 |
278
287
  |---|---|---|---|
279
- | **ⓐ 不同家族** | 这次变更要「决定」什么 —— 一个 PASS/FAIL、一道门禁、一条安全规则 | **实现** 错了 | 换一个模型家族的审阅者(`auto-decorrelation`) |
280
- | **ⓑ 首次真实使用** | 你正要去相信一个数字、一个计数,或某次扫描的输出 | **你测量的方式** 错了 | 拿一个真实目标真跑一次,然后用眼睛看那份结果 |
281
- | **ⓒ 记录接地** | 你写下了别人会据以行动的主张、数字或引用 | **主张** 错了 | 找一个没写过它的人,把它说的重新测一遍 |
282
- | **ⓓ 撤回并观察** | 你加了一个测试、一道守卫或一项检查,并相信它在护着你 | **锚** 错了 —— 那道检查是装饰 | 把它所守护的东西删掉,确认 *正是那一条* 检查变红 |
283
-
284
- **你不必每次都把四条跑满,这是设计如此。** 一行小修一条都不配;一次会返回判定的变更配得上 ⓐ;
285
- 一个已经公开出去的数字配得上 ⓑ 加 ⓒ;一道新加的守卫配得上 ⓓ;而一个不可逆的面 —— publish、
286
- delete、history rewrite —— 配得上四条里它的失败模式所暴露的那些,并且拿不准时就多跑一条。多堆
287
- 几位审阅者,跟多加一条轴不是一回事。
288
-
289
- 还有一条轴坐在这四条之外,因为它换掉的是 *你站在谁的地面上*,而不是 *你检查什么*:**立场
290
- (standpoint)** —— 当一次变更跨进另一个框架时,从目标方自己的仓库与规则去跑这份 diff,而不是
291
- 从你对它们的理解出发
292
- ([`field_verdict_crossfamily_gate.md §7`](knowledge/shared/harness-core/field_verdict_crossfamily_gate.md))。
288
+ | **ⓐ 不同家族** | diff + 作者的框架叙述 | **实现** 错了 | 换一个模型家族的审阅者(`auto-decorrelation`) |
289
+ | **ⓑ 立场 (standpoint)** | diff + **目标框架自己的正典** | **你引用的那条规约是不是真这么说** | 在那个框架自己的仓库与规则里去跑这份 diff ([`§7`](knowledge/shared/harness-core/field_verdict_crossfamily_gate.md)) |
290
+ | **ⓒ 隔离接地** | 作者写下的那些句子 + 此刻的这棵树 | **主张** 错了 | 找一个没写过它的人,把它说的重新测一遍 |
291
+ | **ⓓ 第三方对面** | 问题 + **别人的代码库** | **这是不是早就被解过了** · 你的变更会碰到别人仓库的哪里 | 在一个无关的第三方仓库里看同一个问题 |
292
+ | **ⓔ 首次真实使用** | 一个实打实的目标 | **你测量的方式** 错了 —— 量具的量具 | 拿一个真实目标真跑一次,然后动手核对那份结果 |
293
+ | **ⓕ 撤回并观察** | 把接线删掉之后的那棵树 | **锚** 错了 —— 那道检查是装饰 | 把它所守护的东西删掉,确认 *正是那一条* 检查变红 |
294
+
295
+ **你不必每次都把六条跑满,这正是设计** —— 别做乘法,要 **挑**:
296
+
297
+ ```
298
+ 一行小修(typo · gitignore) 一条都不烧。连 ① 的坐标系都不必 —— 答案只有一个时,
299
+ 栽一套坐标系本身就是开销
300
+ 普通代码变更(可逆) ⓔ 首次真实使用 + ⓕ 撤回
301
+ 判定 · 门禁代码 + ⓐ 不同家族 —— 判定逻辑正是那种「与作者共享同一份乐观」的
302
+ 审阅者会 **结构性地** 漏掉的东西
303
+ 会碰到别人框架的变更 + ⓑ 立场 —— 就算堆三个家族,若三个都吃下了你的框架叙述,
304
+ 「那份正典是不是真这么说」就没有人去看
305
+ 超大型 · 不可逆 + ⓒ 隔离 + ⓓ 第三方对面。全部烧一遍
306
+ ```
307
+
308
+ ⚠️ **ⓓ 第三方对面最贵,而且独有的收成最小。** 可偏偏那少数几条全都是 **跨边界** 的那一类(别人
309
+ 早就废弃掉的规则 · 别人的仓库 import 了你的文件)。在又小又可逆的变更上,这类条目 **根本不会出现**;
310
+ 而在又大又不可逆的时候,恰恰就是这两样会变成事故。成本正当化的位置就在那里。
311
+
312
+ **为什么这一套不会被基础模型的进步取代** —— 一条轴是由 **输入** 定义的,不是由 *审阅者的能力*
313
+ 定义的。模型再强,**「没拿到的信息」它依然看不见。** 脚手架会随着模型变好而脱落,但 **输入边界上的
314
+ 去相关不会脱落**,而单个作者按定义就走不出自己的输入。🟥 诚实的边缘地带:如果 agent **自己用工具
315
+ 去取更多输入**,这条边界就会变模糊 —— 外部判定确实认为「整个存储从未被完整使用」和「异常被吞掉」
316
+ 这两条 ⓐ · ⓒ 也能抓到(因为它们会自己 grep)。反过来,「别人的仓库当年废弃掉的某条规则」
317
+ **用工具也取不到** —— 你压根没有理由去访问那个项目的评审历史。ⓓ 留下来的位置就在那里。
318
+
319
+ > 🟥 **引用之前必须读的限制**:这张六轴表是 **n=1**(一份产物 · 一次会话 · 一位作者)。这些轴之间
320
+ > 的「不重叠」究竟是结构性的、还是那一天的偶然,**尚未测量**。而且为了把作者的自评剥掉,把 16 条
321
+ > 发现 **抹去出处** 交给另外两个家族的分类器做盲判之后,作者归给 ⓓ 的 **5 条里有 3 条被判成了别的
322
+ > 轴** —— 那三条不是「非它不可」,而是「别的轴漏掉了」。表里的归属请照此打折读。
293
323
 
294
324
  > **诚实说明 —— 这不是一个干净的分层,而这正是重点。** 工序 ① 和 ③ 与引擎是同一种材料做的,
295
325
  > 所以下面那层用到了上面那层。这个矛盾在 *主语* 上化解:**引擎** 是 FH 施加于你的工作的东西,
@@ -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?
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: fh-three-layer-canon
3
- description: FH 를 설명하는 3층 정본 — 3단 공정(엔진을 벼리는 순서) · 4대 엔진(그 능력) · 5대 정체성(사람이 실제로 쓰는 기능). 층별 명명 규칙과 4축 검증의 정의를 포함한다.
3
+ description: FH 를 설명하는 3층 정본 — 3단 공정(엔진을 벼리는 순서) · 4대 엔진(그 능력) · 5대 정체성(사람이 실제로 쓰는 기능). 층별 명명 규칙과 6축 검증의 정의를 포함한다(§1-a 최초 4축 · §1-a-2 2026-08-16 확장).
4
4
  date: 2026-08-09
5
5
  tags: [canon, three-layer, engines, identity, verification-axes]
6
6
  ---
@@ -52,9 +52,39 @@ tags: [canon, three-layer, engines, identity, verification-axes]
52
52
  범위 밖 · 절대 안 함
53
53
  ② 중간 탈상관 가속화 축을 골라 동시에 친다. **곱하지 말고 골라라** — 병렬화 자체엔
54
54
  방향이 없다(축은 판단 회로가 고른다)
55
- ③ 마무리 4축 태우기 §1-a 의 축으로 태운다. **적대검증 하나가 아니다**
55
+ ③ 마무리 6축 태우기 §1-a-2여섯 축으로 태운다. **적대검증 하나가 아니다**
56
56
  ```
57
57
 
58
+ > 🟥 **이 줄은 2026-08-16 까지 「4축」이었다 — 갱신을 놓쳤던 것이지 별개 개념이 아니다.**
59
+ > 같은 날 `§1-a-2` 가 4축을 6축으로 확장했는데 이 요약줄이 안 따라와서, **`CLAUDE.md` 는 「6축」
60
+ > 이고 여기는 「4축」인 상태가 존재했다.** 그 사이 외부 계열이 작성한 문서 한 건이 실제로 이 줄을
61
+ > 읽고 ③단계를 「4축」으로 서술했다(weekly_audit_2026-08-16 🟥-4).
62
+ >
63
+ > 🟥 **더 위험한 절반은 숫자가 아니라 문자다 — 같은 글자가 두 배열에서 다른 축을 가리킨다.**
64
+ >
65
+ > | 문자 | §1-a (옛 4축) | §1-a-2 (현 6축) |
66
+ > |---|---|---|
67
+ > | ⓐ | 다른 계열 | 계열 *(동일)* |
68
+ > | **ⓑ** | **첫 실사용** | **입장** ← 옛 ⓑ 는 현 **ⓔ** 로 밀렸다 |
69
+ > | ⓒ | 기록 그라운딩 | 격리 그라운딩 *(대응)* |
70
+ > | **ⓓ** | **되돌림 실측** | **3자 대면** ← 옛 ⓓ 는 현 **ⓕ** 로 밀렸다 |
71
+ > | ⓔ | — | 첫 실사용 |
72
+ > | ⓕ | — | 되돌림 실측 |
73
+ >
74
+ > ✅ **2026-08-17 부로 마커도 이 배열이다** — 날짜 ≥ 2026-08-17 인 마커는 `axes-run` 이
75
+ > **기호 여섯 글자(ⓐ~ⓕ)**를 요구하고, 그 이전 마커는 옛 ASCII 넷을 그대로 쓴다(소급 강제 없음).
76
+ > **표기법이 곧 배열 선언**이라 감사자가 grep 한 번으로 판별한다. 남은 어긋남은 **하나뿐** —
77
+ > `standpoint:` 값의 enum 을 **검증하는 코드가 아직 0줄**이다. 아래 「옛 배열」 서술은 유예일
78
+ > 이전 마커를 읽을 때만 유효한 이력이다. 옛 배열로 쓴 줄을
79
+ > 기계가 **조용히 다른 축으로 읽으며 오류를 내지 않는다.** 확장은 기존 마커 전부를 무효화하므로
80
+ > **운영자 결정 사항으로 열려 있다** — 그때까지 마커를 쓸 때는 **옛 배열**을 쓰고, 산문으로
81
+ > 논할 때는 §1-a-2 의 6축을 쓴다. 이 어긋남을 **알고** 쓰는 것이 현 규율이다.
82
+ >
83
+ > 🟥 그리고 ③단계는 **「결정론적 기계 스크립트」가 아니다.** 여섯 축 중 다섯이 모델/에이전트
84
+ > 판단이고, 기계 앵커가 붙은 축은 현재 **되돌림 하나뿐**이다(§ 아래 «자평이다» 절). ③을
85
+ > pre-commit·exit code 로 서술하면 그건 **커밋 경계의 4축 게이트**(회귀·적대·팬텀·매니페스트)를
86
+ > 말하는 것이며, 둘은 부분적으로만 겹치고 **서로 대체하지 않는다**(`CLAUDE.md` §명칭 충돌).
87
+
58
88
  **이건 도구 목록이 아니라 투입 순서다.** 축 없이 병렬부터 던지면 노이즈가 늘고,
59
89
  태우기부터 하면 태울 게 없다. 근본 명제(운영자, 2026-08-09):
60
90
 
@@ -102,7 +132,7 @@ branch-claim 게이트 ① 영혼 필수 «무엇을 성공으로 볼 것
102
132
 
103
133
  **이 층(바깥 하네스를 빌린다)은 이미 정본화돼 있다** — `harness_verification_core_extended.md`
104
134
  (2026-08-01, PR #225, ARC CLOSED): "Extended = 멀티하네스 클러스터에서 디스패치된 검증 도구,
105
- 대상 하네스 자신의 검증 독트린 로드 금지(그게 탈상관의 요점)." 실증 N=2(qasp↔FH 슬라이스,
135
+ 대상 하네스 자신의 검증 독트린 로드 금지(그게 탈상관의 요점)." ⚠️ 인용은 원문 그대로다 — 그 정체성의 이름은 2026-08-16 에 **「멀티하네스 클러스터」 → 「하네스 클러스터」** 로 줄었다(「멀티」와 「클러스터」가 둘 다 복수를 뜻해 중복이었다). 내용 불변, 상세는 `ship_readiness_gate.md` §①-naming. 실증 N=2(qasp↔FH 슬라이스,
106
136
  7건 신규 접지 발견) + `feedback_decorrelation_axis_matches_failure_mode`(2026-08-07, mate PR
107
137
  #8, reps=3): 코어 결함은 하네스 무관 일치(6/6), **주변부 발견의 클래스가 하네스별로 갈린다**
108
138
  (같은 형태를 이 절이 지금 다시 보고 있다). ⚠️ 이 절의 초판은 이 선례를 못 찾고 "자리가 없다,
@@ -161,7 +191,18 @@ measurement_needs_control]])에 있다. 표본이 지지하는 건 "바깥 하
161
191
  **사례 2개**(gitignore vs 게이트)뿐이다. ⓓ 의 «자기 스코프가 가장 나쁘다» 가 구조적인지
162
192
  그날 우연인지는 **미측정** — 다음 세션들에서 같은 표를 채워 봐야 안다.
163
193
 
164
- ### §1-a — 마무리 «4축» (2026-08-09 실측으로 정의)
194
+ ### §1-a — 마무리 «4축» (2026-08-09 실측으로 정의) — 🟥 **§1-a-2 로 확장됨. 이 절만 읽고 인용하지 마라**
195
+
196
+ > **이 배열은 현행이 아니다.** 산문 정본은 `§1-a-2` 의 **6축**이다. 이 절은 그 6축이 어떻게
197
+ > 도출됐는지의 **이력**으로 남긴다(§1-a-2 가 이 절을 덮지 않는다고 명시하므로 삭제하지 않는다).
198
+ >
199
+ > 🟥 **인용 전에 반드시**: 아래 문자 ⓑ·ⓓ 는 §1-a-2 에서 **다른 축을 가리킨다** — 옛 ⓑ(첫 실사용)
200
+ > → 현 **ⓔ**, 옛 ⓓ(되돌림) → 현 **ⓕ**. 표는 §1 요약줄 아래에 있다. 이 절의 문자를 그대로
201
+ > 6축 문맥에 옮기면 **조용히 다른 축을 지목하게 된다.**
202
+ >
203
+ > ⚠️ **이 절의 배열은 2026-08-17 이전 날짜의 마커에만 유효하다** — 그 날짜부터 마커도 §1-a-2 의
204
+ > 6축(기호 키)을 요구한다. 옛 마커를 **읽을** 때는 여기가 맞고, 새로 **쓸** 때는 §1-a-2 가 맞다.
205
+ > 산문/기계 어긋남은 해소됐고, 남은 잔여는 `standpoint:` 값 검증이 없다는 것 하나다.
165
206
 
166
207
  3단계를 오래 «적대검증» 이라고 불렀으나, 그건 **넷 중 하나**다. 각 축은 **다른 것이 틀린
167
208
  경우**를 잡고 **서로를 대체하지 못한다**:
@@ -183,6 +224,82 @@ measurement_needs_control]])에 있다. 표본이 지지하는 건 "바깥 하
183
224
  (`[[feedback_decorrelation_not_fanout_cost_boundary]]`).
184
225
 
185
226
 
227
+ ### §1-a-2 — 4축 → **6축** 확장 (2026-08-15 실측 · 2026-08-16 정본화)
228
+
229
+ 위 네 축은 **2026-08-09 실측의 것이고 그대로 유효하다.** 그 뒤 한 산출물(qasp 1막 조건 배치 수리)
230
+ 에서 **두 축이 더 섰다.** 이 절은 앞 절을 대체하지 않고 **덧붙인다** — 날짜 박힌 측정을 덮지 않는다.
231
+
232
+ 🟥 **확장의 근거가 되는 명제 — 이게 표보다 중요하다**:
233
+ > **축은 «얼마나 적대적인가»로 갈리지 않는다. «무엇을 받았는가»로 갈린다.**
234
+ > 받는 것이 같으면 리뷰어를 몇 명 붙여도 **같은 사각이 남는다.**
235
+ > ⇒ 「근원은 적대검증」은 **정본과 어긋난다.** 적대성은 **자세**지 축이 아니다 — 아무 축에나
236
+ > 얹을 수 있고, 얹어도 그 축이 못 보는 것은 여전히 못 본다.
237
+
238
+ | 축 | **받는 것** | 무엇이 틀린 경우 |
239
+ |---|---|---|
240
+ | ⓐ 다른 계열 | diff + 저자의 프레이밍 | 구현 |
241
+ | **ⓑ 입장** (신규) | diff + **대상 하네스의 정본** | **인용한 규약이 정말 그런가** |
242
+ | ⓒ 격리 그라운딩 | 저자가 쓴 문장 + 지금의 트리 | 주장 |
243
+ | **ⓓ 3자 대면** (신규) | 문제 + **남의 코드베이스** | **이미 풀린 문제 아닌가** · 내 변경이 남의 레포를 어디서 만지나 |
244
+ | ⓔ 첫 실사용 | 실물 대상 한 건 | 재는 방식(계기의 계기) |
245
+ | ⓕ 되돌림 실측 | 배선을 지운 트리 | 앵커 |
246
+
247
+ **저자 자평을 걷어낸 자리**: 발견 16건을 **출처를 지운 채** 봉인된 정답키와 함께 **레포 밖 cwd·
248
+ 헤드리스**로 다른 계열 분류자 **둘**에게 독립 판정시켰다. 채점 11/15 · 12/15, 상호 일치 13/15(87%),
249
+ 사전 등록한 반증 조건(일치율 50% 미만) 미발동.
250
+ 🟥 **그리고 그 판정이 저자를 반증했다** — 저자가 ⓓ에 귀속시킨 **5건 중 3건**을 둘 다 **다른 축**
251
+ 으로 판정했다("저장소 전수 미사용"=격리 · "예외 삼킴"=계열). **그 셋은 축이 필요했던 게 아니라
252
+ 다른 축이 놓친 것**이다. 살아남은 것은 2건이고, 그 2건에 대해서만 두 계열이 독립으로 나머지 다섯
253
+ 축을 «구조적 불가»로 판정했다.
254
+
255
+ **왜 기반 모델 발전으로 대체되지 않나**: 축은 *리뷰어의 능력*이 아니라 **입력**으로 정의된다.
256
+ 모델이 세져도 **「받지 않은 정보」는 여전히 못 본다.** 스캐폴딩은 벗겨지지만 **입력 경계 탈상관은
257
+ 벗겨지지 않고**, 단일 저자는 정의상 자기 입력을 벗어날 수 없다.
258
+ ⚠️ 정직한 가장자리: 에이전트가 **도구로 스스로 입력을 가져오면** 경계는 흐려진다(그래서 위 3건이
259
+ 다른 축으로 넘어갔다). 반대로 「남의 레포가 과거에 폐기한 규칙」은 **도구로도 못 가져온다** —
260
+ 그 프로젝트의 리뷰 이력에 접근할 이유가 없기 때문이다. 거기가 ⓓ가 남는 자리다.
261
+
262
+ ✅ **기계층이 6축으로 확장됐다 (2026-08-17, 운영자 승인).** 아래는 그 상태와 **남은 잔여 하나**다.
263
+ ```
264
+ axes-run: ⓐ~ⓕ 마커 날짜 ≥ 2026-08-17 이면 pre-commit 이 **기호 여섯 글자를 요구**한다
265
+ axes-run: a/b/c/d 그 이전 날짜의 마커는 옛 네 글자 그대로 (소급 강제 없음)
266
+ standpoint: ⓑ 는 **자기 필드**가 정본이고, `axes-run` 은 `ⓑ=→standpoint` 포인터만 든다
267
+ (이중 기록 회피). 포인터가 있는데 그 줄이 비면 **죽은 포인터로 차단**
268
+ ⚠️ 🟥 **값 자체의 enum 검증은 여전히 0줄** — 이게 남은 잔여다
269
+ ⓓ 3자 대면 ✅ 기록할 자리가 생겼다 (`ⓓ=`)
270
+ ```
271
+ 🟥 **판별자는 마커 파일명의 날짜다**(`< 2026-08-17` = 옛 4축). 표기를 가른 이유는 미관이 아니라
272
+ 실측이다: 두 배열은 **같은 글자가 다른 축을 가리킨다**(옛 `b`=첫실사용 → 지금 **ⓔ**, 옛 `d`=되돌림
273
+ → 지금 **ⓕ**). 같은 글자를 쓰면서 의미만 바꾸면 **조용히 다른 축으로 읽히고 오류가 안 난다** —
274
+ `not found ≠ 0` 의 형제다.
275
+
276
+ ⚠️ **다만 「표기법이 배열을 선언한다」는 명제는 반증됐다** — 이 절의 초판이 그렇게 적었고, 같은 날
277
+ ⓓ3자대면 축이 코퍼스를 손으로 세어 반례를 냈다: `axes-run` 보유 **53건 중 기호 키 4 · 혼용 1**,
278
+ 그리고 **기호 4건 중 2건이 2026-08-10 자이면서 옛 4축 의미**(`ⓑ 첫실사용` · `ⓓ 되돌림`)다. 훅은
279
+ 그 셋을 안 읽으니 커밋에는 영향이 없고, 틀린 답을 받는 쪽은 **감사자**다. 표기 정렬은 «앞으로 쓸
280
+ 때 옛 줄을 복붙하지 않게» 하는 값이지 **소급 판별자가 아니다**.
281
+
282
+ ⚠️ 그리고 **날짜 비교 자체가 프로덕션에서 도달 불가 분기**다 — 훅 호출부가 마커 경로를 `${TODAY}`
283
+ 로 구성하므로 `mdate` 는 항상 오늘이다. **기존 마커를 지킨 것은 그 상수가 아니라 경로 구성**이고,
284
+ 8일 전 `crossfamily:` 확장이 컷오프 없이 성립한 이유도 같다. 숨기지 않고 적는다.
285
+
286
+ **승인의 전제였던 「기존 마커 전부 무효화」는 반증됐다(2026-08-17 실측).** 훅은
287
+ `.axes_23_passed_{브랜치}_{오늘}.marker` **한 개만** 검증하고 과거 마커 재검증 경로가 없다:
288
+ 디스크 마커 **190개** 중 커밋이 막히는 건수는 **0**, 실제 비용은 유예일 이후 **51건이 「어느
289
+ 배열인지 읽을 수 없다」**는 것 — 파손이 아니라 **미측정**이다. 그래서 처방이 「고친다」가 아니라
290
+ **「어느 배열인지 말하게 만든다」**(표기 정렬)가 됐다. 이식성은 bash 3.2 + BSD grep, 4개 locale
291
+ × 6키 전부 HIT · known-negative 0 으로 선행 실측했다(Linux/GNU grep 은 CI 가 첫 측정).
292
+ 형식 정본 = `.claude/rules/fh_4axis_gate.md §Marker axis fields` · 픽스처 25레인 =
293
+ `scripts/test_marker_axes_run_lanes.sh`.
294
+
295
+ > **한계 — 인용 전에 읽어라**: **n=1**(한 산출물 · 한 세션 · 한 저자). 축의 «비중복»이 구조적인지
296
+ > 그날 우연인지는 **미측정**이다. 축은 **사전 등록되지 않았다**(ⓓ는 세션 도중에 생겼고 그 뒤에
297
+ > 무엇을 잡았나를 셌다 — 사후 분류 편향). 분류자는 **실물을 안 봤고** 저자가 쓴 요약 16문장만
298
+ > 받았다 — 걷어낸 것은 «출처 지식»이지 «저자의 서술»이 아니다. 비용은 부분 실측(서브에이전트
299
+ > 합계 ≈ 1.23M 토큰, 사람 시간 미측정).
300
+
301
+
302
+
186
303
  ### §1-c — 자기 대조를 **상시 의무**로 만든 근거 (그리고 그 표본의 한계)
187
304
 
188
305
  `CLAUDE.md` 가 «3층 자기 대조는 상시 의무 · 트리거는 발화가 아니라 자산 접촉» 을 상주로 싣는다.
@@ -282,7 +399,7 @@ measurement_needs_control]])에 있다. 표본이 지지하는 건 "바깥 하
282
399
 
283
400
  | # | 정체성 | 사람이 얻는 것 |
284
401
  |---|---|---|
285
- | ① | 멀티하네스 클러스터 | 한 태스크를 여러 하네스에 태우고 그 사이에서 거버넌스가 계산된다 |
402
+ | ① | 하네스 클러스터 | 한 태스크를 여러 하네스에 태우고 그 사이에서 거버넌스가 계산된다. 하위 기제 **크로스하네스** = 없는 능력을 호출해 쓰고, 지어야 할 것이 보이면 흡수한다 |
286
403
  | ② | 프로젝트 인큐베이터 | 새 하네스가 **태어난 자리에서 걷는** 상태로 나온다 |
287
404
  | ③ | 거버넌스 게이트 | 못 나갈 것이 기계적으로 막힌다 |
288
405
  | ④ | 프런티어→조직 전파 | 바깥에서 온 것이 조직 안까지 착지한다 |
@@ -221,13 +221,71 @@ marker, never replacing it. Closed enum, same discipline as `crossfamily:`'s thr
221
221
  not / did not / did not look* split (a free-prose field would let an unrun check read as a clean
222
222
  pass):
223
223
 
224
+ **🟥 DECIDE IN THIS ORDER — first match wins. Do not pick by matching a description.**
225
+
226
+ ```
227
+ Q1. Did anything EXECUTE in the target's repo — a command, a script, a suite?
228
+ NO, I only read files → tier1b(<harness>) STOP.
229
+ NO, I did not touch its repo → tier1 STOP.
230
+ YES → continue to Q2
231
+ ⚠️ tier2 AND tier2b BOTH REQUIRE EXECUTION. This question is first precisely so the
232
+ next one cannot be used to reason backwards into "tier2 must be the non-executing rung."
233
+ Q2. Was the target's own LOCAL / gitignored wiring visible (settings, consent bindings,
234
+ node-local state) — i.e. its real installed runtime, not a bare clone?
235
+ NO (bare clone, tracked content only) → tier2(<harness>)
236
+ YES (the target's real runtime) → tier2b(<harness>)
237
+ Q3. Was it run by a DIFFERENT operator of the target harness, not you?
238
+ YES → tier3(<harness>) (supersedes Q2)
239
+ ```
240
+
241
+ **Why the procedure exists rather than more definition.** `tier2` vs `tier2b` is **wiring
242
+ visibility**, NOT execution-vs-reading — both execute. But `tier2b`'s gloss names "the target's
243
+ real runtime," which reads as *"tier2b is the execution rung"*, and a reader then infers that
244
+ `tier2` must therefore be the non-executing one.
245
+
246
+ 🟥 **RETRACTED (2026-08-17) — the sim evidence formerly cited here is withdrawn.** This paragraph
247
+ read: *"after all three were corrected to say EXECUTED CODE, two independent blind Sonnet reps STILL
248
+ graded a pure cold-read `tier2`"*, and quoted one rep's reasoning verbatim. Those runs had
249
+ **`tool_uses: 0`** — the agents never opened a file, so the quoted reasoning is a cold guess about
250
+ text it did not read, and the grades measure nothing
251
+ (`tracks/_meta/fh_completed_2026-08-16.md:690`). The live re-run **inverted** the result at
252
+ **reps=1**, below this repo's `reps>=3` bar. **Neither direction is established**; do not restore
253
+ the numbers and do not cite the inversion either.
254
+
255
+ What remains, and it is enough to justify ordering the questions: the enum's *wording* really does
256
+ place the execution claim on `tier2b`'s line, so a reader can reach "then `tier2` is the
257
+ non-executing one" **by the text alone** — that is a property of the text, checkable by reading it,
258
+ and it needs no sim. Ordering the questions removes the inference instead of arguing with it.
259
+
224
260
  ```
225
261
  tier1 content-only review — no standpoint decorrelation (the default
226
262
  unless upgraded; NOT itself a failure, most changes have no target
227
263
  standpoint to borrow)
228
- tier2(<target-harness>) peer-simulated — the reviewer instantiated/ran the TARGET's own repo
229
- (a local clone, real content) and executed the change from that
230
- standpoint. Closes shared-body-path defects; a BARE clone cannot see
264
+ tier1b(<target-harness>) STATIC standpoint read — the reviewer read the TARGET's own files
265
+ (cold, from the target's repo, without the author's framing) and
266
+ adjudicated the change against them, but executed NOTHING. Added
267
+ 2026-08-16 because its absence was actively harmful: a run of exactly
268
+ this shape was recorded as `tier2`, since tier1 undersold it and no
269
+ nearer value existed. A missing rung does not stay empty — it gets
270
+ filled by the next one up. Real but weak: see «execution is the
271
+ load-bearing half» below before crediting it.
272
+ tier2(<target-harness>) peer-simulated — the reviewer EXECUTED CODE in the TARGET's own repo
273
+ (a local clone, real content) and observed the result.
274
+ 🟥 DISCRIMINATOR — «reading the target's real files is NOT this rung».
275
+ 🟥 RETRACTED (2026-08-17): the «two blind Sonnet sims both graded a
276
+ cold-read tier2 … 0/2» measurement that stood here is WITHDRAWN —
277
+ tool_uses: 0, the agents never opened a file, so the grades and the
278
+ quoted reasoning measure nothing (fh_completed_2026-08-16.md:690).
279
+ The live re-run INVERTED it at reps=1, below this repo's reps>=3 bar.
280
+ Neither direction is established; restore no number here.
281
+ The AMBIGUITY it was cited for is still checkable WITHOUT a sim: the
282
+ earlier wording said «instantiated/ran the target's own repo», and
283
+ «ran» admits «operated within / engaged with», which a read satisfies.
284
+ That is a property of the text — read the two lines and see it.
285
+ THE TEST, and it is mechanical: **name the command you executed and
286
+ the output you observed.** Cannot name one → `tier1b`, always. An
287
+ agent that read files, however cold and however many, executed
288
+ nothing. Closes shared-body-path defects; a BARE clone cannot see
231
289
  the target's gitignored local wiring (settings, consent bindings,
232
290
  node-local state) — that gap is inherent to a clone, not a defect in
233
291
  a given run. Named exception, not a loophole: if the reviewer's own
@@ -259,6 +317,60 @@ DEGRADED_NOT_RUN did not — target was accessible, standpoint revi
259
317
  UNKNOWN did not look — applicability itself was never assessed
260
318
  ```
261
319
 
320
+ **🟥 Execution is the load-bearing half — a static standpoint read is largely subsumed by the other
321
+ axes (operator decision, 2026-08-16).** The reason to pay for a standpoint at all is not that
322
+ someone re-read the diff from a different chair; it is that **the target harness was actually made
323
+ to run.** Operator's framing, verbatim: *"그 하네스의 입장에서 정적리뷰하는 것만으로도 뭔가 잡을
324
+ 수야 있겠지만 그건 다른 검증축으로도 커버가 아마 가능하지 않을까. 진짜로 중요한 건, 그 하네스
325
+ 입장에서 돌려봐서 구동이 되는지를 로컬에서 완벽하게 확인하는 것."* A static read competes with
326
+ cross-family review (§3) and isolated grounding for the same defect classes and mostly loses —
327
+ those axes are cheaper and already routine. Execution has no substitute, because the class it
328
+ catches is *unreachable by reading*: the target's own environment differs (absent files, different
329
+ resolution order, a lane that has never once run there).
330
+
331
+ **Measured the same day this was written, on one delta (pmh-dev PR #72)**:
332
+
333
+ | Arm | Found |
334
+ |---|---|
335
+ | `tier1b` static standpoint read (isolated agent, target's own files, cold) | **1** — a 2-tier-vs-3-tier root-path resolution mismatch |
336
+ | Running the target's own `selfcheck.sh` to completion, locally | **2 more**, both invisible to any read: a test fixture keying on a file that does not exist in that repo, and an npm-shipping check whose premise is inapplicable there. One of them printed **neither `FAIL` nor `❌`** anywhere in its output (it used its own vocabulary, `INSTRUMENT ERROR`) and needed a `bash -x` trace to locate — a defect that is *structurally* undiscoverable by reading, since the reader must already know which string to look for. |
337
+
338
+ n=1 delta, same operator, same session — reported as a directional observation, not a rate. It is
339
+ recorded because it is the first time the two arms were run *separately on the same change* and
340
+ their yields could be attributed. ⚠️ **Do not read the table as "static review is worthless"** — it
341
+ found a real defect that shipped a fix. Read it as: *static is the half that has substitutes;
342
+ execution is the half that does not.*
343
+
344
+ **🟥 What dynamic standpoint review DOES and DOES NOT subsume (operator + governor, agreed
345
+ 2026-08-16 after both arms were measured).** Operator's proposal: *"FH가 기여하는 다른 레포들도 다
346
+ 마찬가지일 테니, 그쪽 입장에서의 동적 리뷰는 소넷을 상주시켜 돌려보는 거지. 이건 굳이 짓지 않아도
347
+ 동적 입장리뷰만 잘 시킨다면 알아서 커버될 거라고 생각해."* Agreed, with one boundary — and the
348
+ agreement is evidenced, not deferential:
349
+
350
+ - **SUBSUMES: building per-target instruments.** Do not write a new scanner for each contributed
351
+ repo, language, or defect class. Execution is **stack-agnostic**; an instrument is not. Measured
352
+ the same day: `degrade_direction_scan.sh` is bound to shell/python *and* to verdict vocabulary —
353
+ a faithful Python port of a real upstream defect scores CLEAN, because the fail-open value was
354
+ ordinary *data*, not a verdict token. An instrument carries a scope boundary into every repo it
355
+ visits; running the target's own suite does not.
356
+ - **DOES NOT SUBSUME: adversarial reading.** **Execution is a detector, not a generator.** It
357
+ answers *does this break · does it fire · does the environment differ*; it cannot answer *is
358
+ there a defect class nobody has instrumented yet*. The upstream `clawd-on-desk` PR #888 defect
359
+ was **not** found by running that repo's tests — it was found by reading and conceiving the
360
+ unreadable-file case, after which a test was written. And where the target ships no runnable
361
+ suite, execution has nothing to run at all.
362
+
363
+ **The measured split, same delta, same day**: static read → **1** finding · execution → **2** more.
364
+ Neither arm was zero, which is the whole result. So both run: reading generates the hypothesis,
365
+ execution confirms or refutes it, **and the hypothesis that survives becomes a test left behind in
366
+ the target** — which is exactly what our own upstream contribution did (the survivor-lane pattern,
367
+ `tracks/_meta/fh_signal_2026-08-16_clawd-survivor-lane-air.md`).
368
+
369
+ **Consequence for the marker**: a `tier2`/`tier2b`/`tier3` claim asserts that something was RUN. If
370
+ the review only read, the honest value is `tier1b` — and since `tier1b` is explicitly the weak rung,
371
+ recording it truthfully is what surfaces that the execution arm is still owed. (This rule exists
372
+ because it was broken on the day it was written: see the `tier1b` entry above.)
373
+
262
374
  **Residual this enum split names rather than hides**: for a harness pair with one shared human
263
375
  operator (this repo and a sibling field harness the same operator also runs), `tier3` is either
264
376
  unreachable or collapses into "the same author ran it in the other repo" — which is exactly the