ADR-0047 — HOW-outside floor-2 (P-11 4-enum) の CI hard-block 昇格

Status: accepted · Date: 2026-07-03 · folio v1.1.0 · design-intent 本文への明示 HOW primitive 混入を検出する floor-2 (P-11 4-enum 構文検出) を soft-warn から CI hard-block (violation・exit 1・merge block) へ昇格する — staged rollout の完了段 (実測 = 生涯 真陽性 1 件・偽陽性 0)。 ADR-0043 §2.2 が定めた staged rollout (soft-warn → 誤検出率の実測 → 許容内なら新 ADR で CI hard gate 昇格) の次段 = 完了段の記録である。 ADR-0028 §2.3 の what-only = agent-only 立場は覆さない — 意味判定 (概念 HOW) は LLM ceiling のままとし、 意味判定の射程外にある構文検出可能な部分集合のみを deterministic block へ引き上げる refine である。 user 承認 = Tier B grill (2026-07-03) で方向確定 + 本 ADR 本文承認。

§1. Context

ADR-0043 §2.2 は、 design-intent (WHAT/WHY) 本文への HOW 混入を止める floor-2 = P-11 4-enum の保守的構文検出 (環境変数の具体値 / バイナリ path / OS コマンド / 明示ツール起動) を導入し、 その enforcement を staged rollout — 当初は soft-warn (exit 非影響の advisory) で着地させ、 誤検出率を実測し、 許容内と確認後に新 ADR (user 承認) で CI hard gate へ昇格 — と定めた。 本 ADR はその昇格判断を記録する。

実測結果 (self-host corpus): soft-warn 稼働以来、 floor-2 が emit した warn は生涯ちょうど 1 件rules.html 内の環境変数具体値 (真陽性)。 これは P-11 違反として言い換えで解消済みであり (検出 → remediate の意図されたループが 1 巡実証された)、 偽陽性は 0 件、 現 corpus の warn は 0 件である。 観測母数が 1 件と薄いことは判断時に明示的に認識されている (§3)。

昇格を今行う根拠は 3 つ。 (1) 検出は構文限定であり「この文は意味的に HOW か」という曖昧判定を一切含まない — 誤検出を構造的に抑える設計そのものが統計的立証の薄さを補う。 (2) 正当な primitive 言及には <code> 包みという有界な逃げ道が既に存在する (§2.2) — 万一誤検出が出ても是正コストは「囲んで終わり」であり、 不当 merge block が行き止まりにならない (bounded-and-fixable)。 (3) folio を導入する downstream consumer が未観測の現時点は、 hard 化の影響が実質 folio 自身に閉じる最も安い窓である — consumer が現れた後の昇格は移行負担を伴う。 方向は Tier B 一括 grill (2026-07-03) で user が確定した。

§2. Decision

§2.1 floor-2 の hard-block 昇格 (scope と様式)

folio validate の HOW-outside gate のうち floor-2 (P-11 4-enum 構文検出) を violation (exit 1・merge block) へ昇格する。 4 primitive カテゴリ (env-var-value / binary-path / os-command / tool-invocation) は一括昇格とする — 実測で偽陽性 0 のためカテゴリ別段階化の便益がなく、 gate ロジックの分岐複雑化だけが残るため。 floor-1 (照会リンク存在) は warn 据置 — 本昇格の実測対象外であり誤検出特性が別物のため、 昇格判断を別途行う。 exit code 意味論は ADR-0020 の 0 = clean / 1 = violation / 2 = tool error を不変とし、 専用 exit code は新設しない。 scope は spec_path (design-intent 空間) のみ・constitution は skip・decisions/ (frozen) と research は対象外 — ADR-0043 §2.2 の scope を変えない。

§2.2 正式な逃げ道 = code/機械層 mask の明文化

floor-2 は可視の地の文のみを走査し、 <code> / <pre> / aside.machine-readable / chrome 領域は検出前に mask される (既存設計)。 本 ADR はこれを「正当な primitive 言及の正式経路」として明文化する: spec が構造や慣習の説明のために環境変数名・ツール名等へ言及する必要があるときは、 コード書体 (<code>) で括る — これは同時に「実装断片は地の文 (散文の規範) ではなくコードとして明示的に区別されている」という P-11 の意図の表現でもあり、 逃げ道と規律が一致する。 明示 suppression marker / per-spec allowlist は導入しない (YAGNI) — 地の文で読ませたい正当な primitive という実例は self-host corpus に一度も現れておらず、 例外機構の追加は ADR-0028 が退けた複雑性の再導入になるため。 実例が出た時点で §2.4 の経路で再検討する。

§2.3 ADR-0028 §2.3 との関係 (syntactic-subset refine)

規範 REQ-CI-012 (what-only gate の merge block MUST) は当初から block を規範宣言しており、 ADR-0028 §2.3 が定めたのは「その enforcement 実体を deterministic hard gate にせず LLM ceiling に置く」という実装判断だった — 根拠は意味的判定の機械化精度 (偽陽性/偽陰性) の低さ。 本 ADR はこの立場を覆さない。 明示 primitive の有無は構文の問題であって意味判定の射程外 (ADR-0043 §2.2 の切り分け) であり、 本昇格は REQ-CI-012 の enforcement 実体を二相化する refine である: 構文検出可能な部分集合 (P-11 4-enum) = deterministic floor block / 概念 HOW (P-3 portability 依存の記述) = 従来どおり LLM ceiling (spec-review-ssot lens) の advisory。 supersede ではなく、 ADR-0028 の精度懸念が当たる領域 (意味判定) は agent-only のまま残る。

§2.4 撤退条件 (rollback plan)

昇格後に「正当な地の文であって <code> 包みによる是正が合理的でない」confirmed な偽陽性が 1 件でも観測されたら、 floor-2 の報告 channel を warn へ戻し (channel flip のみの可逆変更・検出ロジックは不変)、 事象を issue tracker に記録した上で suppression 機構の要否を再検討する。 判断者は user (P-10 と同じ承認系)。 「<code> で囲めば足りる誤検出」は撤退事由にならない — それは §2.2 の正式経路による是正である。

§2.5 配布 (plugin 固定・全 consumer 適用)

配布は ADR-0043 §2.3 の plugin 固定 (gate toggle の userConfig 変数を新設しない) を踏襲し、 昇格は folio validate を使う全 consumer に自動適用される。 self-CI のみ block とする 1 段緩衝は採らない (§4)。 deployment corpus (任意 consumer の spec) 上の誤検出率は未測だが、 §2.2 の有界な逃げ道と §2.4 の撤退条件がその不確実性を引き受ける。

§3. Consequences

§4. Alternatives

§5. Trace