# 사실 인덱스 산출물과 추출기는 개행을 LF 로 고정한다. # # 왜: 추출기는 `\n` 으로 쓰는데 `core.autocrlf=true` 머신(Windows 기본)에서 체크아웃하면 # 워킹트리 파일이 CRLF 가 된다. 그러면 PRD §Success Metrics 의 "재현성 · 편차 0" # (추출 2회 실행 후 `diff` 빈 출력) 판정이 머신마다 갈린다 — 값이 아니라 개행 때문에. # 실측 확인: 재체크아웃 후 commits.admin.jsonl 에 CR 1,157개가 생기고 diff 가 깨졌다. docs/_meta/index/* text eol=lf # 사실 인덱스 산출물과 추출기의 개행을 LF 로 고정한다. # # 소유: `.claude/prds/insuniverse-docs-00-protocol.prd.md` §`.gitattributes` — EOL 정책 # (2026-08-06, `12-index-runtime` 회부 5 수용). `.gitmodules` 와 같은 루트 인프라 부류다. # # 왜: 이 저장소는 `core.autocrlf=true` 이고 `.gitattributes` 가 없었다. 그 상태에서는 커밋된 LF # 산출물이 워킹트리에서 CRLF 로 나오므로, 추출기 `--emit-yaml` 출력(LF)과 커밋본의 **바이트 # 비교가 항상 실패**하고 인덱스의 `set_sha256` 도 플랫폼마다 갈린다. 재현성 지표가 산출물을 # 실제로 덮으려면 EOL 이 먼저 고정돼야 한다. # # 범위 제한: 전역 `* text=auto` 를 걸지 않는다. 아래 두 glob 만 건드려 기존 추적 파일의 EOL 을 # 흔들지 않는다. 범위 검사는 Validation `#5c-0`(규칙 집합 정확 일치) · # 적용 검사는 `#5c`(check-attr 출력 파싱) · 결과 검사는 `#5c-2`(전역 churn 0건). # # 위 `docs/_meta/index/*` 는 10-index-git 축이 같은 사유로 먼저 올린 규칙이다(main). 아래 두 줄과 # 겹치는 부분은 결과가 동일하고(둘 다 `eol=lf`), `docs/_meta/verify/*.mjs` 는 위 규칙이 덮지 # 않으므로 양쪽을 모두 남긴다. docs/_meta/index/*.yaml text eol=lf docs/_meta/verify/*.mjs text eol=lf # `12-index-runtime` 회부 12 수용 (2026-08-10, 마일스톤 4). 위 두 glob 과 **같은 사유**의 범위 # 확장이다 — `policy-candidates.runtime.jsonl` 은 추출기 `--emit-jsonl` 출력(LF)을 그대로 커밋하고 # 커밋본과 재방출의 바이트 비교가 재현성 지표 본체다. 이 줄이 없으면 `core.autocrlf=true` 가 # 워킹트리를 CRLF 로 만들어 그 비교가 **첫 실행부터 항상 실패**한다. docs/_meta/index/*.jsonl text eol=lf # ops-30-reconcile M0. 위 `docs/_meta/index/*` 규칙과 **같은 사유**의 범위 확장이다. # # 왜: 층 3 원장(`ops/reconcile/reconcile.jsonl`)은 `--check` 가 CR 1바이트에 `OPS_RC_LEDGER_NOT_LF` # 로 실패시키는 파일이다(UI5 — LF 고정). 이 저장소는 `core.autocrlf=true` 이고 이 경로에는 # 속성이 없었다. 반사실 실측(scratch repo · add → clone → checkout): 커밋된 LF 2행이 체크아웃 # 후 CR 2개를 얻었다. 같은 저장소 방증: 속성 밖 `ops/db/rows.jsonl` 워킹트리에 CR 669개. # 그대로 두면 (가) 신선 체크아웃마다 `_harness/golden/**` 교차 오라클이 `GOLDEN_CHECK_NONZERO` # 로 죽고 (나) M2 가 판정 행을 넣는 순간 생산 `--check` 가 **항상** 실패한다 — # LF 를 강제하려던 게이트가 무조건 실패로 퇴화한다. # # 범위 확대: `ops-doc-reconcile` M0 축 A (UI8 — 우산 핵심 제약 6 배타 소유를 이 M0 에 한해 면제). # # 앞 판은 `ops/reconcile/**/*.jsonl` 하나였고 나머지 `ops/**` 는 속성 밖이었다. 그 상태의 실측 # (`git checkout-index -a --prefix=/` 사본에서 `tr -dc '\r' | wc -c` 합계): # # ops/_meta/verify-ops.sh 1098 # ops/db/rows.jsonl 669 # ops/reconcile/_harness/m0.sh 531 # ops/statements/_harness/m0.sh 437 # ops/db/requests/01-ops-snapshot.sql 416 # ops/db/requests/02-schema-scan.sql 82 # ops/cells/spike-m0-style-axis.txt 52 # ops/_meta/golden.txt 22 # ──── # 3307 # # **커밋된 바이트에는 CR 이 한 개도 없다** — 위 8건 전부 `git show HEAD: | tr -dc '\r'` 가 # 0이다. CR 은 `core.autocrlf=true` 가 체크아웃 때 넣는다. 그래서 조치는 blob 재작성이 아니라 # 이 파일 한 곳이고, 그 근거로 아래 네 줄이 `git checkout-index` 사본의 CR 을 0으로 만든다. # # 왜 이 4확장자인가: `.sh` 는 신선 체크아웃에서 실행 자체가 깨지고(위 1098), `.jsonl` 은 층 2·3 # 원장이 `OPS_INV_LEDGER_NOT_LF` / `OPS_RC_LEDGER_NOT_LF` 로 CR 1바이트에 죽는 계약이며, # `.txt` 는 `golden.txt` 재현 오라클 본체고, `.sql` 은 층 1' 수령 질의의 정본이다. 그 밖의 # 확장자(`.mjs` · `.md` · `.yaml` · `.json` · `.lock`)는 이 M0 가 건드리지 않는다 — 게이트가 # 그것들을 개행 정규화 해시(`verify-ops.sh` 의 `sha256Text`)로 뜨므로 EOL 에 결박되지 않는다. ops/**/*.sh text eol=lf ops/**/*.jsonl text eol=lf ops/**/*.txt text eol=lf ops/**/*.sql text eol=lf