{ "schemaVersion": 1, "runId": "2026-09-10-1033", "project": "document-haness", "record": "docs/document-haness/tech-log-studio/pipeline-gate-exit-codes/case/case-exit-code-read-behind-a-pipe.md", "startedAt": "2026-09-10T10:33:45+09:00", "finishedAt": "2026-09-10T11:00:39+09:00", "stages": [ { "id": "S1", "name": "코드베이스 → SSOT", "skill": "analyzing-codebase-for-tech-log", "runBy": "subagent", "status": "DONE", "skipReason": "", "skillEcho": "Do not turn inference into observation in the final document.", "inputs": [ "docs/document-haness/final/document.md", "docs/document-haness/final/evidence/raw/**", "docs/document-haness/final/evidence/meta/**" ], "outputs": [ "docs/document-haness/final/document.md", "docs/document-haness/final/evidence/meta/argparse-absent-scripts.json", "docs/document-haness/final/evidence/meta/what-the-three-print-for-help.json", "docs/document-haness/tech-log-studio/tech-log-tree.json" ], "gates": [ { "cmd": "python3 scripts/verify-project-layout.py document-haness", "exit": 0 }, { "cmd": "python3 scripts/build-tech-log-tree.py document-haness", "exit": 0 }, { "cmd": "python3 scripts/verify-tech-log-tree.py document-haness", "exit": 0 }, { "cmd": "node .agents/skills/writing-tech-log-records/scripts/check_evidence.mjs document-haness --repo", "exit": 0 } ], "notes": "대조 모드다. 분석을 새로 하지 않고 SSOT 가 증거 원문과 어긋나는지만 봤다. S3 이 올린 어긋남 하나가 실물이었다 — 증거 정본 argparse-absent-scripts.txt 의 「ARGPARSE 없음」이 4줄인데 SSOT 는 셋이라고 적었다. 「argparse 가 없는 것(넷)」과 「--help 를 위치 인자로 먹는 것(셋)」을 한 숫자로 섞은 것이다. SSOT 네 곳(:155 절 제목 · :157 · :176 · §9)을 고치고, 절 제목이 바뀌어 앵커를 가리키는 세 곳(계약 2 · 기록 frontmatter 1)을 함께 고쳤다. 증거 메타 둘의 proves·doesNotProve 도 같은 오산을 담고 있어 고쳤다 — 그것은 사람이 적은 주장이다. exitCode·sha256·bytes·command 는 실행이 적은 값이라 안 건드렸고, raw 원문은 한 글자도 안 건드렸다(메타 8건의 sha256 을 다시 계산해 원문과 일치 확인). runs/.../stage/S3-before.md 는 과거 사본이라 옛 앵커를 그대로 두었다. 그 밖에 §1~§9 의 인용 블록 다섯을 raw 와 diff 로 대조했고 §7 의 원장 인용이 runs/virtualization/2026-09-09-1052/run.json:78 에 실재하는 것까지 확인했다. 오케스트레이터가 증거 원문과 코드로 다시 세어 넷인 것을 독립으로 확인했다. 판단이 필요해 안 고친 것 둘 — guards/ 증거 둘을 인용하는 기록이 없고(warn 2건), sourceRepository.path 가 worktree 가 아니라 원본 경로를 가리킨다(verified 칸이 사유를 적는다)." }, { "id": "S2", "name": "SSOT → 분해 계약", "skill": "deriving-tech-log-root-tree", "runBy": "orchestrator", "status": "SKIPPED", "skipReason": "이 글감이 tech-log-tree.json 에 이미 PROMOTE · dispositionReview CONFIRMED 로 있다 (candidates[DH-C01], target=case:exit-code-read-behind-a-pipe). 분해를 다시 하지 않았다.", "skillEcho": "", "inputs": [ "docs/document-haness/final/document.md", "docs/document-haness/tech-log-studio/tech-log-tree.json" ], "outputs": [ "docs/document-haness/tech-log-studio/tech-log-tree.json" ], "gates": [ { "cmd": "python3 scripts/build-tech-log-tree.py document-haness", "exit": 0 }, { "cmd": "python3 scripts/verify-tech-log-tree.py document-haness", "exit": 0 } ], "notes": "build 는 파생 칸(file·publication·status·ssotSha256)만 다시 채운다. 사람이 적은 칸은 그대로다." }, { "id": "S3", "name": "글감 → 기록", "skill": "writing-tech-log-records", "runBy": "subagent", "status": "DONE", "skipReason": "", "skillEcho": "**옮겨 적었다고 확인한 것이 아니다.** 앞선 기록에서 코드를 가져오거나 기억으로 경로를 쓰면", "inputs": [ "docs/document-haness/tech-log-studio/tech-log-tree.json", "docs/document-haness/final/document.md", "runs/document-haness/2026-09-10-1033/stage/S3-before.md" ], "outputs": [ "docs/document-haness/tech-log-studio/pipeline-gate-exit-codes/case/case-exit-code-read-behind-a-pipe.md" ], "gates": [ { "cmd": "python3 scripts/studio-body.py docs/document-haness/tech-log-studio/pipeline-gate-exit-codes/case/case-exit-code-read-behind-a-pipe.md -o /tmp/s3-body.md", "exit": 0 }, { "cmd": "node --experimental-transform-types .agents/skills/writing-tech-log-records/scripts/check_body.mjs /tmp/s3-body.md", "exit": 0 }, { "cmd": "node .agents/skills/rewriting-technical-prose-naturally/scripts/check_prose.mjs --warn docs/document-haness/tech-log-studio/pipeline-gate-exit-codes/case/case-exit-code-read-behind-a-pipe.md", "exit": 0 }, { "cmd": "node .agents/skills/writing-tech-log-records/scripts/check_evidence.mjs document-haness --repo", "exit": 0 }, { "cmd": "python3 scripts/verify-tech-log-tree.py document-haness", "exit": 0 } ], "notes": "기록은 이미 있었고 서브에이전트가 계약·SSOT 와 대조해 세 곳을 고쳤다. (1) 요약 칸의 백틱 — 평문으로 렌더링되는 칸이다. (2) 요약이 「계약 문서에까지 들어갔다」고 적었는데 SSOT 는 「확인 등급 확인함으로 적었다」까지만 말한다. SSOT 가 뒷받침하는 문장으로 바꿨다. (3) 본문이 「열넷 중 셋이 argparse 를 쓰지 않는다」로 시작하면서 바로 아래 표에 「없음」을 넷 적어 두었다. 증거 정본 argparse-absent-scripts.txt 의 「ARGPARSE 없음」이 4줄이므로 표가 맞고 문장이 틀렸다 — 셋→넷, 남은 둘→남은 셋으로 고쳤다. 오케스트레이터가 증거 원문과 코드로 다시 세어 넷인 것을 확인했다. 같은 오산이 SSOT·계약·증거 메타에 그대로 있다는 것을 서브에이전트가 크게 적어 올렸고, SSOT 를 고치는 것은 자기 단계 밖이라 손대지 않았다 — S1 로 돌렸다. check_prose 경고 2건(CASE·POSIX 약어)은 남겼다. CASE 는 frontmatter 의 kind 값이고 POSIX 는 SSOT 가 쓰는 표준 명칭이라 풀어 쓰면 보호 구간을 건드린다." }, { "id": "S4", "name": "기록 → 그림", "skill": "technical-visualizer", "runBy": "orchestrator", "status": "SKIPPED", "skipReason": "그림이 필요 없다. 세 관문 중 셋째에 걸린다 — 본문의 「왜 그 둘만인가」 절이 argparse 유무와 --help 결과를 표 하나로 답하고 있어, 같은 것을 그림으로 다시 그리면 옆 문단이 이미 말한 것을 되풀이한다. 계약의 이 노드에도 assets 가 없다.", "skillEcho": "", "inputs": [], "outputs": [], "gates": [], "notes": "이 프로젝트의 final/assets 는 비어 있다. check-figure-text.py 와 check-figure-overlap.py 는 볼 그림이 없어 돌리지 않았다." }, { "id": "S5", "name": "AI 티 제거", "skill": "rewriting-technical-prose-naturally", "runBy": "subagent", "status": "DONE", "skipReason": "", "skillEcho": "| Sentences are all short and choppy | Rejoin with `~기 때문에`, `~다 보니`, `~어서`; break only where the subject changes |", "inputs": [ "docs/document-haness/tech-log-studio/pipeline-gate-exit-codes/case/case-exit-code-read-behind-a-pipe.md", "runs/document-haness/2026-09-10-1033/stage/S5-before.md" ], "outputs": [ "docs/document-haness/tech-log-studio/pipeline-gate-exit-codes/case/case-exit-code-read-behind-a-pipe.md" ], "gates": [ { "cmd": "node .agents/skills/rewriting-technical-prose-naturally/scripts/check_prose.mjs --warn docs/document-haness/tech-log-studio/pipeline-gate-exit-codes/case/case-exit-code-read-behind-a-pipe.md", "exit": 0 }, { "cmd": "node .agents/skills/rewriting-technical-prose-naturally/scripts/style_profile.mjs docs/document-haness/tech-log-studio/pipeline-gate-exit-codes/case/case-exit-code-read-behind-a-pipe.md", "exit": 1 }, { "cmd": "python3 scripts/studio-body.py docs/document-haness/tech-log-studio/pipeline-gate-exit-codes/case/case-exit-code-read-behind-a-pipe.md -o /tmp/s5-body.md", "exit": 0 }, { "cmd": "node --experimental-transform-types .agents/skills/writing-tech-log-records/scripts/check_body.mjs /tmp/s5-body.md", "exit": 0 }, { "cmd": "node .agents/skills/writing-tech-log-records/scripts/check_evidence.mjs document-haness --repo", "exit": 0 }, { "cmd": "python3 scripts/check-preservation.py runs/document-haness/2026-09-10-1033/stage/S5-before.md docs/document-haness/tech-log-studio/pipeline-gate-exit-codes/case/case-exit-code-read-behind-a-pipe.md", "exit": 0 } ], "notes": "서브에이전트가 아홉 곳을 고쳤다. 전부 문장을 잇거나 문단 순서를 옮긴 것이고 삭제한 문장도 새로 쓴 문장도 없다(68문장 → 63문장). check-preservation.py 가 「보호 구간 변화 0건 · 유보 감소 0종」으로 확인했다 — 윤문이 수치·코드·인용·URL 을 건드리지 않았고 유보 표현도 안 지웠다는 뜻이다. style_profile.mjs 는 exit 1 로 그대로 적는다. 관문이 아니라 측정이고 문서 계약이 이것에만 「error 0」을 안 붙였다. 이유 연결어미는 5.9 → 9.5 로 기준 안에 들어왔고 문장 평균 길이는 41.6 → 45 로 기준(48~75) 밖에 남았다. 서브에이전트가 남은 짧은 문장 22개를 전부 열어 보고 재현 조건 단계·수치 한 줄·코드로 넘기는 도입·정의 한 줄·방향 전환이라 잇지 않았다고 적었다. 수치를 맞추려고 문장을 넣지 말라는 것이 스킬의 규칙이다. 서브에이전트가 사실 어긋남 하나를 올렸다 — 본문이 「이 기록의 증거 여섯 개」라고 적었는데 frontmatter 의 evidence 는 다섯이다. 수치는 보호 구간이라 S5 가 못 고친다고 판단해 넘겼고, 오케스트레이터가 frontmatter 를 세어 확인한 뒤 다섯으로 고쳤다. check-preservation 은 이 고침을 못 잡는다 — 한글 수사는 아라비아 숫자가 아니라서 보호 구간 비교에 안 걸린다. 이 검사기의 알려진 한계다." }, { "id": "S6", "name": "일한 사람의 목소리", "skill": "writing-as-the-person-who-did-it", "runBy": "subagent", "status": "DONE", "skipReason": "", "skillEcho": "고치는 방법은 하나뿐이다. **자료에 남아 있는 사람의 흔적을 찾아서 제자리에 놓는다.**", "inputs": [ "docs/document-haness/tech-log-studio/pipeline-gate-exit-codes/case/case-exit-code-read-behind-a-pipe.md", "docs/document-haness/final/document.md", "docs/document-haness/tech-log-studio/tech-log-tree.json", "docs/document-haness/final/evidence/meta/*.json", "scripts/capture-evidence.py", "runs/document-haness/2026-09-10-1033/run.json", "runs/document-haness/2026-09-10-1033/stage/S6-before.md" ], "outputs": [ "docs/document-haness/tech-log-studio/pipeline-gate-exit-codes/case/case-exit-code-read-behind-a-pipe.md" ], "gates": [ { "cmd": "node .agents/skills/writing-as-the-person-who-did-it/scripts/check_voice.mjs docs/document-haness/tech-log-studio/pipeline-gate-exit-codes/case/case-exit-code-read-behind-a-pipe.md", "exit": 0 }, { "cmd": "node .agents/skills/rewriting-technical-prose-naturally/scripts/check_prose.mjs --warn docs/document-haness/tech-log-studio/pipeline-gate-exit-codes/case/case-exit-code-read-behind-a-pipe.md", "exit": 0 }, { "cmd": "python3 scripts/studio-body.py docs/document-haness/tech-log-studio/pipeline-gate-exit-codes/case/case-exit-code-read-behind-a-pipe.md -o /tmp/s6-body.md", "exit": 0 }, { "cmd": "node --experimental-transform-types .agents/skills/writing-tech-log-records/scripts/check_body.mjs /tmp/s6-body.md", "exit": 0 }, { "cmd": "node .agents/skills/writing-tech-log-records/scripts/check_evidence.mjs document-haness --repo", "exit": 0 }, { "cmd": "python3 scripts/check-preservation.py runs/document-haness/2026-09-10-1033/stage/S6-before.md docs/document-haness/tech-log-studio/pipeline-gate-exit-codes/case/case-exit-code-read-behind-a-pipe.md", "exit": 0 } ], "notes": "흔적 있음. 두 곳을 넣었고 둘 다 근거를 파일과 칸으로 댔다. (A) 「왜 그 둘만인가」 절에 이 런이 겪은 어긋남을 그 대목에 놓았다 — 두 숫자를 섞어 넷을 셋으로 적었고 그것이 분석 문서 네 곳과 증거 메타 둘에 실렸으며 증거 원문에서 줄을 다시 세어 고쳤다는 것. 근거는 이 원장의 S1·S3 notes 다. (B) 「손으로 적지 못하게 했다」 절에 도구를 쓴 사람의 말을 옮겼다 — scripts/capture-evidence.py 의 docstring :5 와 :9 다. 기록이 기능만 적고 목표와 이유는 안 적던 자리다. 인용부호나 백틱으로 감싸지 않고 평문으로 녹였다 — check-preservation 이 새로 생긴 인라인코드와 「」 직접인용을 「새로생김」으로 세기 때문이다. 낱말은 docstring 그대로다. 안 넣은 것도 적었다. 「처음에는」·「고민 끝에」·「놀랍게도」는 자료에 없어 한 건도 안 썼고, 커밋 메시지는 capture-evidence.py 가 아직 untracked 라 흔적이 없다 — 찾아봤고 없었다. 이미 있던 사람의 흔적 셋(같은 착각이 한 번 더 났다 · 셸 래퍼도 됐지만 · 처음 판에서는 이 도구도 인자를 잘못 먹었다)에는 손대지 않았다. 서브에이전트가 계약의 어긋남 하나를 올렸다 — candidates[DH-C03].reason 이 「한 번밖에 안 써서」라고 적는데 이 도구가 적은 메타가 여덟 건이다. 자료와 어긋나 그 문장을 근거로 못 쓴다고 판단하고 안 넣었다. 오케스트레이터가 메타를 세어 확인한 뒤 계약을 「이 저장소 하나에서만 써서 … 실행 여덟 건이 전부 이 프로젝트의 증거 수집이고 다른 프로젝트나 브라우저 캡처에 걸어 본 적이 없다」로 고쳤다." }, { "id": "S7", "name": "Studio 저장", "skill": "publishing-tech-log-to-studio", "runBy": "orchestrator", "status": "SKIPPED", "skipReason": "Studio 반입을 요청받지 않았다. 이 배치에서 Studio 브라우저 세션은 통합 세션 A 가 소유하고, 게시 권한이 저장 권한과 분리돼 있지 않아 무인 저장이 막혀 있다 (A-studio-change-requests.md 의 CR-001). 화면을 열지 않았다.", "skillEcho": "", "inputs": [], "outputs": [], "gates": [], "notes": "기록 frontmatter 의 id 와 studio 는 비어 있다. 저장한 적이 없다는 뜻이고 그대로 둔다." } ] }