Skip to content

[DONE] 정리 2단계 PR 9 — 새로 쓴 글에 금지 낱말이나 셋 나열, 「이 문서는」 첫머리, 맺음 요약이 있으면 check:voice 가 줄마다 짚는다 - #33

Merged
patternflow-bot merged 5 commits into
devfrom
claude/studio-cleanup-2-pr9-9rs5zr
Oct 15, 2026
Merged

patternflow-bot merged 5 commits into
devfrom
claude/studio-cleanup-2-pr9-9rs5zr

Conversation

@patternflow-bot

@patternflow-bot patternflow-bot commented Oct 15, 2026 •

Copy link
Copy Markdown

studio / https://claude.ai/code/session_01BuCv1gYnJ5iaHHEEYBb9qb

정리 2단계 계획서 표의 PR 9 이다. 새로 쓴 글에 npm run check:voice 를 돌리면 금지 낱말, 쉼표로 늘어놓은 셋, 「This document describes」 같은 첫머리, 「In conclusion」 같은 맺음 요약을 파일:줄 로 짚는다. CI 에는 넣지 않았고, PR 을 열기 전에 손으로 돌린다(계획서 D6).

좋아지는 것: 일꾼 글의 기계 같은 말투를 올리기 전에 줄마다 짚는다 — 읽을 글이 덜 거슬린다

할 일

한 일

web/scripts/voice-lint.ts 를 새로 썼다. 명령 이름 check:voice 는 #25 가 package.json 에 넣어 두었다. 출력은 찾은 것마다 한 줄, 파일:줄 규칙 걸린 말 이다.

규칙은 §2.10 마지막 문단과 k9 가 적은 넷이다.

  • banned: docs/voice-banned.txt 의 말. 영어는 대소문자를 가리지 않고 낱말 단위로 어미까지 잡는다(ensure 는 ensures·ensured·ensuring, robust 는 robustly). 여러 낱말로 된 말은 줄이 바뀌어도 잡는다. 한국어는 쓴 그대로 어디서나 잡는다. 목록 파일 머리에 적힌 약속 그대로라 목록에 말을 더해도 스크립트는 안 고친다.
  • threes: 쉼표로 늘어놓은 셋. 영어는 §2.10 의 예 "fast, simple, and reliable" 처럼 마지막 앞에도 쉼표가 있고, 셋의 낱말 수가 같고(1~3), 관사 따위로 시작하지 않는 것이다. 한국어는 「빠르고, 간단하고, 안정적인」처럼 앞 둘이 -고·-며·-한·-적인 따위로 끝나는 것이다.
  • opener: 문장 첫머리의 「This document/guide/page/PR/module … describes/covers/introduces/provides …」, 「In this guide, we …」, 「이 문서는 … 설명」.
  • closer: 문장 첫머리의 「In conclusion」「In summary」「To sum up」「Overall,」, 그리고 「결론적으로」「요약하면」「요컨대」.

읽는 범위.

  • 인자가 없으면 잠금 검사와 같은 기준(PR 8 의 scripts/lib/pr-base.ts) 뒤로 이 브랜치가 더한 줄만 읽는다. 새 파일은 추적 안 된 것까지 전부, 고친 파일은 hunk 의 + 쪽 줄이다. 인자가 파일이면 그 파일 전부, - 면 stdin 을 마크다운으로 읽는다(PR 본문용).
  • 글만 읽는다. 마크다운은 코드 펜스·인라인 코드·태그·링크 대상·URL 을 뺀 글과 프런트매터 값, HTML 은 script·style 밖의 글이다. ts·tsx·js 는 TypeScript 파서로 찾은 주석·문자열·JSX 글을 읽고, 정규식 리터럴과 String.raw 템플릿은 패턴이라 건너뛴다. C·C++·Kotlin 은 주석, Python 은 주석과 docstring, 셸·YAML 은 주석만 읽는다.
  • 경로, 큰따옴표·「」·『』 안의 인용, 「Writing voice」 제목 아래 절은 뺀다. 그 절은 금지하는 말을 인용해야 하는 자리다: k11 이 AGENTS.md 에 붙일 규칙, rfc-cleanup.md §2.10, docs/voice.md. 목록 자체인 docs/voice-banned.txt 도 이유와 함께 EXEMPT 에 두고 뺀다(D3).
  • 기준을 못 찾을 때는 human-lock 과 같다. PF_LOCK_BASE 가 이 클론에 없는 커밋이면 실패, 기준이 없으면 skip(exit 0), PF_DRIFT_STRICT=1 이면 skip 도 실패다.

증거

지금 브랜치(a40d2db, web/):

  • npm run check:voice(인자 없음): exit 0. 스크립트가 자기 자신을 읽고도 걸리지 않는다. 패턴을 정규식 리터럴로 둔 까닭이다.
    base: 42bb578 (the merge-base with origin/dev)
    read: 271 added lines in 1 file
    
    check:voice: nothing found
    
  • npm run typecheck: exit 0. npm run lint: exit 0, ✖ 12 problems (0 errors, 12 warnings). 모두 원래 있던 src/ 경고이고 새 파일에는 없다.
  • npm run check:drift: passed bom, bom-schematic, changelog, editions, features, links-absolute, presets, skipped roadmap(이 컨테이너엔 gh 로그인이 없다, D2). exit 0. CI 의 Drift checks 는 PF_DRIFT_STRICT=1 과 GH_TOKEN 으로 roadmap 까지 돈다.
  • npm run check:ci(dev merge 전 1d30c0c): exit 0, Test Files 35 passed (35), Tests 478 passed (478). merge 로 들어온 것은 changelog·roadmap 검사와 drift 워크플로이고, 검사는 위 check:drift 와 CI 에서 돌았다.
  • npm run check:human-lock: check:human-lock: no locked words changed.
  • git fetch --tags 뒤 npm run doc-map: 1071 links from 214 files, 0 do not resolve. 바뀐 다섯 행은 dev 의 5단계 계획서·진행 기록·editions.ts 것이라 이 PR 과 무관하고, 두 CSV 는 git checkout 으로 되돌렸다.

저장소 밖 스크래치 폴더의 버리는 글에 돌린 결과. bad.md:

 1 ---
 2 title: A robust title
 3 cover: ./robust.png
 4 ---
 5 This document describes the board and what it ensures.
 7 The panel is fast, simple, and reliable. It reads the file, checks the list, and prints the line.
 8 In this guide, we wire it up. Overall, it works.
 9 It's important to
10 note the wrap. Here's the
11 seamless part, utilizing streamlined, empowering, delving and leveraged words.
12 This is cutting-edge and cutting edge.
14 이 문서는 보드를 설명합니다. 빠르고, 간단하고, 안정적인 보드예요.
15 결론적으로 잘 돼요. 다양한 패턴이 효율적으로 돌아요.
17 In conclusion, it works.
19 ## Writing voice
21 robust inside the rule.
23 ### Deeper
25 ensure, still inside.
27 ## After
29 robust again.
bad.md:2    banned  robust
bad.md:5    banned  ensures
bad.md:5    opener  This document describes
bad.md:7    threes  fast, simple, and reliable
bad.md:7    threes  reads the file, checks the list, and prints the line
bad.md:8    opener  In this guide, we
bad.md:8    closer  Overall,
bad.md:9    banned  It's important to note
bad.md:10   banned  Here's
bad.md:11   banned  seamless
bad.md:11   banned  utilizing
bad.md:11   banned  streamlined
bad.md:11   banned  empowering
bad.md:11   banned  delving
bad.md:11   banned  leveraged
bad.md:12   banned  cutting-edge
bad.md:12   banned  cutting edge
bad.md:14   threes  빠르고, 간단하고, 안정적인 보드예요
bad.md:14   opener  이 문서는 보드를 설명
bad.md:15   banned  다양한
bad.md:15   banned  효율적으로
bad.md:15   closer  결론적으로
bad.md:17   closer  In conclusion
bad.md:29   banned  robust

3줄의 경로, 21·25줄의 Writing voice 절은 걸리지 않고, 절이 끝난 29줄은 다시 걸린다. 다른 꼴도 같은 실행에서 봤다.

bad.tsx:1   banned  seamless              /** This module provides a seamless thing. */
bad.tsx:1   opener  This module provides
bad.tsx:4   threes  Fast, simple, and reliable   const s = "Fast, simple, and reliable.";
bad.tsx:5   banned  ensures               const t = `it ensures ${x} works`;
bad.tsx:6   banned  robust                <p title="robust title">We ensure it. {/* a robust jsx comment */}</p>
bad.tsx:6   banned  ensure
bad.tsx:6   banned  robust
bad.tsx:9   banned  robust                // a robust comment before the brace
bad.h:1     banned  Ensure                // Ensure the panel is set.
bad.h:3     banned  robust                /* robust ... */
bad.py:1    banned  Here's                """Here's the docstring."""
bad.py:2    banned  ensure                x = "robust string is not read"  # ensure this comment is
bad.html:2  banned  seamless              <p>This page describes a seamless console.</p>
bad.html:2  opener  This page describes
raw.ts:2    banned  robust                // a robust comment
raw.ts:3    banned  seamless              String.raw`robust \d`, // seamless trailing

(오른쪽은 그 줄의 원문.) 걸리지 않은 것: bad.tsx 의 import … from "./robust-path" 과 /seamless|robust/ 정규식, bad.h 의 C 문자열, bad.py 의 문자열, bad.html 의 <style>·<script>, raw.ts 의 String.raw 안.

깨끗한 글 clean.md: check:voice: nothing found, exit 0. 관사로 시작하는 셋(The cards, the bundles, and the images), 고유명사 셋(Korean, English, and Japanese), U1, SW1, and J4, 인라인 코드의 seamless, 큰따옴표·「」 안의 robust·다양한, 링크 대상·URL·img src 의 robust·ensure·seamless, 코드 펜스 안, ## Writing voice 절, insured·there's 를 담았다.

버리는 고침으로 본 인자 없는 실행. docs/legacy/BUILD_GUIDE_v2.md 5줄 끝에 「In conclusion, it works.」를 붙이고 끝에 「The panel is fast, simple, and reliable.」을 더하고, 추적 안 된 docs/throwaway-voice.md 를 만들었다(돌린 뒤 되돌리고 지웠다).

base: be1c06f (the merge-base with origin/dev)
read: 274 added lines in 3 files

docs/legacy/BUILD_GUIDE_v2.md:5    closer  In conclusion
docs/legacy/BUILD_GUIDE_v2.md:517  threes  fast, simple, and reliable
docs/throwaway-voice.md:3          banned  seamless
docs/throwaway-voice.md:3          opener  This page describes
web/scripts/voice-lint.ts:150      threes  fast, simple, and reliable

check:voice: 5 findings in 3 files

같은 파일 3줄의 「This guide walks」와 321줄의 「ensures」는 원래 있던 줄이라 읽지 않았다. 다섯째 줄은 이 스크립트 주석의 인용을 잘못 짚은 것이다. String.raw 안의 따옴표가 인용 짝을 흐트러뜨려서였고, String.raw 를 건너뛰게 고친 뒤로는 위처럼 nothing found 다.

기준과 인자:

경우 결과
PF_LOCK_BASE 가 없는 커밋 check:voice: PF_LOCK_BASE is 0123…, and this clone has no such commit (check out with fetch-depth: 0), exit 1
origin 없는 얕은 클론 check:voice: skipped, no PF_LOCK_BASE, and no merge-base with origin/dev or origin/main, exit 0
같은 클론에 PF_DRIFT_STRICT=1 같은 줄과 PF_DRIFT_STRICT=1, so a skip fails, exit 1
없는 파일 check:voice: no such file: docs/nope.md, exit 1
docs/voice-banned.txt skipped docs/voice-banned.txt: it is the list the banned rule reads, exit 0
stdin 「Fix the panel. / This PR introduces a robust fix.」 (stdin):3 banned robust, (stdin):3 opener This PR introduces, exit 1

이 본문도 파일로 check:voice 에 돌려 nothing found 였다. 처음엔 규칙의 낱말을 이름으로 든 곳 열두 군데가 걸려서 백틱으로 쌌다.

트리 전체에 돌려 본 수(참고만, 아무것도 고치지 않았다):

읽은 것 banned threes opener closer
추적된 .md·.mdx 197개, 19,393줄 42 104 6 0
추적된 코드·HTML 935개, 213,800줄(4.3초) 23 87 0 1

banned 42 중 대부분은 일지의 「다양한」이고, opener 6 은 「This guide walks」(BUILD_GUIDE.md 등)와 「This file provides」(AGENTS.md)다. 잠긴 글이거나 사람이 쓴 글이라 고치지 않는다. 이 검사는 일꾼이 더한 줄에 쓴다.

실행법

cd web
npm ci
npm run check:voice                          # 이 브랜치가 더한 줄(기준: origin/dev 와의 merge-base)
npm run check:voice -- ../docs/AUDIO_GUIDE.md  # 파일 전부
npm run check:voice -- - < pr-body.md        # PR 본문

가정

  • 기준 브랜치는 dev(머리말). 표가 PR 9 에 적은 한 파일만 고쳤다. CHANGELOG.md, docs/rfc-cleanup-progress.md, doc-map CSV 는 안 고쳤다. 라벨 cleanup·step-2 는 포크에 없어서 달지 않았다.
  • check:ci 에도 drift 워크플로에도 넣지 않았다(D6, 질문 14 의 기본값). 그래서 찾은 것이 있으면 exit 1 로 끝내도 막는 것이 없다. PF_DRIFT_STRICT 는 기준을 못 찾은 skip 에만 쓴다.
  • 규칙은 §2.10 마지막 문단과 k9 가 적은 넷만 짰다. §2.10 의 다른 「Do not」(줄표로 이은 문장, 굵게, 이모지, 「Note:」, 얼버무림, AI 언급)은 사람이 읽을 몫으로 남겼다.
  • threes 는 어림이다. 처음엔 「A, B and C」도 잡았더니 트리의 .md 에서 452개(100줄에 2.3개)가 나왔고 거의 물건 목록이었다. 그래서 §2.10 의 예처럼 마지막 앞 쉼표가 있는 것, 셋의 낱말 수가 같은 것, 관사·소유격으로 시작하지 않는 것만 잡게 줄여 104개가 됐다. 관사 없는 물건 목록(makers, artists, and musicians)은 아직 걸린다. 사람이 보고 넘긴다.
  • 인용은 뺐다. 규칙을 설명하는 글은 예를 인용해야 하고, README 를 따옴표로 인용하는 것은 voice.md 가 권하는 버릇이다. 작은따옴표는 아포스트로피와 섞여서 넣지 않았다.
  • 「Writing voice」 제목 아래 절을 빼는 것은 계획서에 없는 동작이다. k11 이 §2.10 블록을 「## Writing voice (hard rule)」로 붙이면 금지 낱말 목록 때문에 AGENTS.md 가 걸리고, rfc-cleanup.md §2.10 과 docs/voice.md 도 같다. 제목 낱말로 빼서 그 자리만 비킨다.
  • ts·tsx 의 문자열과 JSX 글은 읽는다. 사이트 문구가 거기 있기 때문이다. C 문자열은 시리얼 로그가 대부분이라 읽지 않는다. 코드 파일이 아닌 확장자(json, csv, svg 등)는 인자 없는 실행에서 건너뛰고, 파일로 주면 평문으로 읽는다.
  • 인자 없는 실행은 고친 줄을 통째로 읽는다(hunk 의 + 쪽). 한 낱말만 바꾼 줄도 그 줄의 원래 말까지 읽힌다.
  • 없는 파일을 인자로 주면 skip 이 아니라 실패로 했다. 경로를 잘못 쳐서 통과하는 일을 막는다.
  • 번역체 표시(voice.md 의 Korean 절: ~에 대해, ~를 통해 등)는 목록에 없어서 잡지 않는다. 창작자가 docs/voice-banned.txt 에 더하면 그대로 잡힌다.

for another k

  • k11: 명령 줄은 「check:voice: 손으로, 산문을 새로 쓴 PR 을 열기 전에. 인자가 없으면 기준 뒤로 더한 줄, 파일이나 -(stdin)도 받는다」. §2.10 블록의 제목에 「Writing voice」를 그대로 두어야 이 검사가 그 절을 건너뛴다.
  • k12: 「CI 가 돌리는 것」을 적을 때 check:voice 는 CI 에 없다고 한 줄.

Changelog

Web

  • check:voice points at the habits of generated prose, line by line. Run it by hand on new or rewritten text before a pull request opens. With no arguments it reads the lines the branch adds; it also takes files, and - reads a PR description from stdin. It flags a word from docs/voice-banned.txt, three adjectives or clauses after a serial comma, an opening that says what the text is about and a closing summary, each as file:line. CI does not run it.

Upstream

  • What: Add check:voice (web/scripts/voice-lint.ts), the voice lint of rfc-cleanup.md section 2.10. It flags words from docs/voice-banned.txt, serial-comma triplets, openers and closing summaries as file:line, in the files given or the lines a branch adds. Run by hand, not in CI.
  • Checks: npm run typecheck, npm run lint (0 errors), npm run check:drift, npm run check:ci, npm run check:human-lock, npm run check:voice (throwaway text fails each of the four rules, clean text passes), npm run doc-map (1071 links, 0 unresolved, CSVs restored).
  • Docs map: none

🤖 Generated with Claude Code

https://claude.ai/code/session_01BuCv1gYnJ5iaHHEEYBb9qb

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BuCv1gYnJ5iaHHEEYBb9qb
@patternflow-bot patternflow-bot changed the title [WIP] 정리 2단계 PR 9 [WIP] 정리 2단계 PR 9 — 새로 쓴 글에 금지 낱말이나 셋 나열, 「이 문서는」 첫머리, 맺음 요약이 있으면 check:voice 가 줄마다 짚는다 Oct 15, 2026
… fails on a missing file

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BuCv1gYnJ5iaHHEEYBb9qb
@patternflow-bot patternflow-bot changed the title [WIP] 정리 2단계 PR 9 — 새로 쓴 글에 금지 낱말이나 셋 나열, 「이 문서는」 첫머리, 맺음 요약이 있으면 check:voice 가 줄마다 짚는다 [DONE] 정리 2단계 PR 9 — 새로 쓴 글에 금지 낱말이나 셋 나열, 「이 문서는」 첫머리, 맺음 요약이 있으면 check:voice 가 줄마다 짚는다 Oct 15, 2026
@patternflow-bot
patternflow-bot marked this pull request as ready for review October 15, 2026 01:46
@patternflow-bot
patternflow-bot merged commit 5376b0b into dev Oct 15, 2026
2 checks passed
@patternflow-bot
patternflow-bot deleted the claude/studio-cleanup-2-pr9-9rs5zr branch October 15, 2026 01:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants