ADR-0045 — spec-pack の機械層 dual-audience round-trip (engine w1f)

Status: accepted · Date: 2026-06-23 · folio v1.1.0 · engine epic folio-0dv / follow-up folio-w1f。 ADR-0044 (B6) が 意図的に境界として繰延した「機械層 dual-audience round-trip」(§2.4) を閉じ、 北極星 folio-7wn「非エンジニア×機械 両対応の完璧な文書」の self-host を full 化する設計を確定する。 grounding sweep (wf_378476a0) が実 scope を確定: rules.html の機械層 (data-audience="machine") 106 node のうち 26 EARS SHALL 文は既に round-trip 済で、 真の対象は extractor が意図的に skip する ~71 件の自由文 prose である。 これは contract のどの field からも決定的導出できない人手の自由文ゆえ、 round-trip の依存方向が設計判断となる。 本 ADR は user grill (2026-06-23・全 5 論点合意) の forward decision を記録する prospective ADR で、 実装は後続 w1f cell (2–3 分割) で行う。 ADR-0033 の dual-audience co-author + ADR-0042 の hybrid 生成・ADR-0028 の二層 enforcement を機械層へ拡張する。

§1. Context

ADR-0044 (engine B6) は spec-pack で folio 自身の rules.html を機械 SSoT から生成し、 「engine が folio 文書型を再現できる」を core 無改変で実証した。 ただし §2.4 で主張水準を正直に限定し、 生成物は rules.html の人間層プレゼンを高忠実に再現する一方、 data-audience="machine" の機械層 prose は extractor が非モデル化する、 機械層も含む full dual-audience round-trip は folio-w1f に繰延する、 と境界を明記した。 北極星 folio-7wn「非エンジニア×機械 両対応」を self-host で完成と言い切るには、 この機械層を閉じる必要がある。

grounding sweep (wf_378476a0) が実 scope を確定。 rules.html の機械層 (data-audience="machine") は 106 node あるが、 これは二分される: (a) 26 EARS SHALL 文 = 既に contract の statement field にあり rq-norm fold として生成済 (= round-trip 済)。 (b) ~71 件の自由文 prose (45 段落 + 16 注記 + 10 箇条書き = rationale / context / 運用説明) = extract-rules-spec.sh が意図的に skip し件数を LOG するのみ・contract 未モデル化・生成物に不在。 w1f の真の対象は (b) のみである (「機械層全体が未モデル化」は誤認)。

純生成では閉じない (= 設計判断が必須)。 ~71 件は人手で書かれた自由文で、 contract のどの構造化 field からも決定的に導出できない (例「folio が govern するのは architecture/ の 3 domain…」「cwd で context を即判定…」)。 ゆえに round-trip には (a) 原本 HTML から contract へ機械抽出で取り込む extract 方向か、 (b) opus prose スロットとして再 author するか、 の依存方向の選択が要る。 この判断は ADR-0044 にも engine 設計 doc にも記録が無い。 本 ADR は user grill (2026-06-23・全 5 論点) で合意した forward decision を、 実装に先立ち記録する prospective ADR である。

§2. Decision

§2.1 取り込み方向 = extract (機械抽出で逐語取り込み)

機械層自由文 (~71 件) の round-trip 方向を extract 取り込みとする。 extract-rules-spec.sh を双方向化し、 現在 skip している機械層 prose (段落 / 注記 / 箇条書き) を原本 rules.html から逐語抽出して contract に取り込む。 原本が既に存在する確定テキストである以上、 これは「文書を新たに書く」問題ではなく「既存テキストを機械可読化する」問題であり、 逐語転記ゆえ捏造リスクが構造的にゼロとなる。 folio の確立 doctrine 「決定的に導出できるもの → floor / 意味的なもの → ceiling」(engine 設計) に最も素直に乗る (extract された prose は contract 由来ゆえ floor で忠実性を担保できる)。 skip ロジックを capture ロジックに変えるのが extractor の中核変更だが、 no silent caps 原則を保ち、 取り込んだ件数・残余 (もし境界を残すなら) を LOG する。

§2.2 機械層 DOM form = canonical data-audience (本物の dual-audience)

生成物の機械層 DOM を、 原本と同じ canonical form (正規形) data-audience="machine" で出力する。 現 spec-pack は要件 normative を data-audience 属性を持たない独自 rq-norm fold で出すが、 これを canonical form へ置換し、 機械層自由文も章単位の data-audience="machine" block として出力する。 これにより生成物は ADR-0033 が定義した dual-audience co-author 構造 (machine canonical 子孫 + human 派生 view) を再現し、 folio 自身の物差し REQ-DA-STRUCT-1..5 (人間層 container が機械層子孫を持つ・id 整合・値域 machine|human・機械層 aria-hidden 無し・EARS pattern 整合) と folio_check_dual_audience の検査対象になる = 本物の dual-audience 文書となる。 floor 射程の拡大はコストではなく「engine が自分の dual-audience 規律ごと自己再現できた」という self-host 証明そのものであり、 積極的に取りに行く (部分 round-trip では「full self-host」を半分しか主張できない)。

§2.3 二層 fidelity gate (決定的 floor 集合一致 + 独立 ceiling)

機械層 prose の忠実性を二層で担保する。 §2.1 で extract (逐語コピー) を選んだことで、 忠実性の大部分が決定的に検査可能になる (B6 の opus 作文時より遥かに強い)。 floor = 原本 rules.html の data-audience="machine" テキストと生成物の機械層テキストが両方向で集合一致する (欠落ゼロ = 完全性 / 余計な作文ゼロ = no-fabrication / 逐語一致)。 この照合は extractor の内部ロジックに依存せず原本を直接 grep するため folio の生成 path と独立で、 ADR-0044 §2.3 が指摘した engine=oracle 死角 (生成バグと検証バグの相殺) を踏まない (fail-open しない正当な floor)。 ceiling = 既存 fidelity-spec agent (folio-17n で制度化済) に機械層軸を追加し、 機械的に判定しきれない構造的帰属 (どの prose がどの章のものか)・歪曲の有無を独立 read-only で検査する。 floor 単独通過は ADR-0028 継承の CEILING=PENDING で GREEN を機械的に禁ずる。

§2.4 core 無改変 + scope (rules 1 文書 /tmp 非破壊・schema は tr0 汎用)

core 無改変を既定とする (既定 = 無改変・例外の additive は本段落末尾の汎用 primitive 出現時のみに限る)。 触る対象は pack 側 (extract-rules-spec.sh = spec-pack 固有 / assemble-spec.sh / verify-spec.sh / contract schema) に閉じ、 lib/{common,verify-common,graph-common}.sh + inject-prose.sh既存関数を byte 不変で死守する (extract を選んだため opus slot 機構 = inject-prose.sh に触らない)。 これが保てれば rule-of-three の instance#5 でも core 無改変 = engine core 抽出完了の主張を一層強固にする。 core additive 拡張は「tr0 でも確実に再利用する汎用 primitive が実際に現れた時のみ・既存関数の改変なし」に限る。

scope = 成果物は rules.html 1 文書のみ・生成は /tmp 非破壊 (原本を編集せず validate golden を dirty にしない)。 ただし機械層 prose の contract schema は、 残 3 文書 (verification / relations / self-spec) の self-host (folio-tr0) で再利用を見据えた汎用設計とする (rules で実証し、 残 3 文書は別 cell)。 生成物で実際の rules.html を置換する真の self-host は drift gate を要するため別 follow-up に繰延 (B-scope 非破壊原則との衝突を避ける)。 extract が逐語取り込みゆえ、 原本の stale prose (rules.html §11.2 / §11.5) は事前に folio-ccu で是正してから extract する (stale を正本として contract に焼き付けない)。

§3. Consequences

§4. Alternatives

§5. Trace

拡張対象 (境界): ADR-0044 §2.4 (B6 が「機械層 round-trip は境界」と正直に scope 限定・本 ADR がその境界を閉じる)。 一般化基盤: ADR-0033 (dual-audience = machine canonical SSoT + human 派生 view の 1-DOM co-author を enforcement で担保・生成物がこの構造を再現)。 生成基盤: ADR-0042 (hybrid 生成の決定的 assembler を機械層 block emit へ拡張・core 無改変共用)。 enforcement 継承: ADR-0028 (二層 enforcement を機械層自由文の忠実性へ適用・独立 ceiling で抽出忠実性の死角を突く・CEILING=PENDING)。 self-host target: rules.html の機械層 (data-audience="machine")。 原則接地: P-3 (WHAT/HOW 分離) / P-5 (1 entity = 1 canonical name) / P-10 (ADR 昇格は user 承認) / P-13 (WHAT↔HOW 束縛) / P-14 (人間可読性 = 生成物に適用)。 設計 design-of-record: engine §10 (research domain) + 本 grill grounding sweep (wf_378476a0 = 機械層 106 node の二分・extract 必須を実測確定)。 追跡: bd engine epic folio-0dv / follow-up folio-w1f。 prospective 実装計画: cell-1 (extractor 双方向化 = skip→capture + 機械層 prose schema・tr0 汎用) / cell-2 (assemble-spec canonical data-audience form + verify-spec floor = 原本↔生成物 機械層集合一致 + REQ-DA-STRUCT 適合 + CSS) / cell-3 (fidelity-spec 機械層軸 + 独立 ceiling + user walk gate I)。 前処理: folio-ccu (rules.html §11.2/§11.5 の stale prose 是正を extract 前に land)。 受入: 既存 5 pack + 人間層 spec-pack byte-identity 非回帰 / core git diff 空 (rule-of-three) or core additive のみ / sandbox 全 GREEN / validate clean / 独立 ceiling 捏造ゼロ / user walk = 北極星 full self-host。 follow-up: folio-tr0 (機械層 schema を verification/relations/self-spec へ再利用) / 置換 + drift gate (真の self-host) / folio-1pz (spec-pack 可読性 minor)。 決定の経緯: user grill 2026-06-23 (grounding sweep wf_378476a0 で機械層の実 scope = ~71 自由文を確定し、 全 5 論点を上流→下流順で合意: 方向=extract / form=canonical data-audience / gate=二層 / core=pack 内完結 / scope=rules 1 文書 + tr0 汎用 schema)。 version: 本 ADR 文書版 = 1.1.0 (記録する capability は engine epic folio-0dv・後方互換追加)。