ADR-0020 — folio validate の試作 scope (internal link-integrity + jsonld structural)

Status: accepted · Date: 2026-05-25 · folio v0.4.2-draft · forward (Track 3、 user 承認済、 実装は spawn)

§1. Context

ADR-0003 §2.1folio CLI に validate subcommand を、 CI script に link-integrity を列挙したが、 いずれも未実装で bin/folio help に「実装予定」 と宣言されているのみ。 spec 上は rules.html §10.2 が CI 7 gate (REQ-CI-010〜016) を規範化済だが、 runtime で enforce するのは per-file の 4 hook のみで、 spec 群を横断検証する batch validator が存在しない。

Track 1 (folio inventory) で spec の <head> JSON-LD を scan し @id を scratch 相対 path へ解決する機構 (folio_resolve_relpath / folio_build_relations) を実装済。 Track 2 で ADR-0004 の jsonld 構造 check が per-file hook (check-jsonld-lint.sh) として稼働中。 これらを横断 batch に再利用すれば validate が低コストで実装できる段階に達した。 確定すべきは: validate が試作段階でどの gate を担うか (scope)その tool / 検証方式

前 session で feature-dev が手動発見した broken cross-ref (relations.html §4.4 の inventory-regen.yaml → 実在しない、 commit adf662a) のような内部 link 切れを機械検出する価値が、 本 ADR の動機である。

§2. Decision

§2.1 試作 scope = 内部 link-integrity + jsonld structural の 2 gate

folio validate は inventory と同じ spec 集合 (scratch/{specs,decisions,research}<head> JSON-LD を持つ .html) を横断し、 bash + jq で決定的に検査できる 2 gateを試作実装する:

  1. internal link-integrity (REQ-CI-010 の (b) anchor fragment + (c) 内部 fs reference): 各 spec の JSON-LD relation (dc:references 等の @id) を folio_resolve_relpath で解決し、 (i) target file が存在するか、 (ii) #anchor 付きなら target file 内に当該 id が存在するか を検証する。
  2. jsonld structural (REQ-CI-016 partial = ADR-0004 Option B Light): 各 spec の JSON-LD block を parse + 必須 key (@context / @id / @type) + @context == object を検証する (check-jsonld-lint.sh と同一規範)。

§2.2 試作で defer する gate (Phase X4+)

defer 対象理由解消 timing
external URL check (REQ-CI-010 の (a))network 依存で非決定的・CI 限定。 lychee 等の外部 tool が適 (bash+jq で完結しない)Phase X4+ link-integrity CI script (validate とは別 component)
prose gate (what-only / vocabulary / declarative / EARS coverage / delta marker、 REQ-CI-011〜015)HTML prose の semantic 解析要、 試作の bash+jq では tractable でないPhase X4+ (完成形 validate に段階追加)

これにより specs/README §6.2 の「link-integrity = Phase X4+」 は external 部分に narrowing される: 内部 link-integrity (anchor + fs ref) は本 Track 3 で前倒し実装、 external URL は X4+ 維持。

§2.3 interface / 出力 / exit code

folio validate は inventory/prime と同じく cwd = repo root で動作し、 既定で scratch/ の spec 集合を検査する。 test isolation のため検査 root の override を MUST 提供する (具体 flag / env は HOW = folio-self-spec §9 Bindings / 実装で確定、 fixtures を汚染なく検査するため)。 出力は human-readable な violation report を stdout、 exit code は 0 = clean / 1 = violation 検出 (REQ-CI 「fail = merge block」 に対応) / 2 = tool error (jq 不在等、 fail-closed)

§2.4 plugin-lib batch 再利用 (DRY)

check-jsonld-lint.sh の構造 check ロジックを plugin-lib.sh の関数へ抽出し、 per-file hook (payload の content に対し) と batch validate (file の抽出 block に対し) が同一関数を共用する (behavior-preserving、 sandbox 維持)。 internal link-integrity は bin/folio の既存 folio_extract_head_jsonld / folio_build_relations / folio_resolve_relpath を再利用する。 検証は ADR-0018 cli-golden harness (clean 集合 → exit 0、 broken fixture → exit 1 + report、 golden-diff)。

§3. Consequences

Positive

Negative

Neutral

§4. Alternatives Considered

採用しなかった理由
案 A (採用): 内部 link-integrity + jsonld structural の 2 gate、 bash/jq、 既存機構再利用、 cli-golden 検証決定的・低コスト・高価値 (broken cross-ref 検出)、 inventory/hook の再利用度が最大
案 B: REQ-CI 7 gate を試作で全実装prose gate (what-only/vocabulary 等) は semantic 解析要で bash+jq では tractable でない。 試作 scope 過大
案 C: external URL check も今含める (lychee)network 依存で非決定的、 cli-golden の byte-exact と相性悪。 外部 tool 依存追加。 X4+ CI script が適所
案 D: jsonld を ajv (JSON Schema) で完成形検証ADR-0004 が試作は Option B Light と決定済。 validate も同 Light を踏襲 (段階的成長)
案 E: batch validator を作らず per-file hook のみhook は新規 Write しか見ず、 既存 spec 群の横断 regression (link 切れ) を捕捉できない。 batch が必要
案 F: ADR 化せず REQ-CI-010/016 の純粋実装扱いscope narrowing (内部のみ) + tool 選択 (bash/jq vs lychee/ajv) は ADR-0004/0018 と同型の mechanism decision。 trace 価値があり user 承認で起票 (2026-05-25)

§5. Trace